From ae7d6c0c2fb84ba533294454486bbae9e8e3f5cc Mon Sep 17 00:00:00 2001 From: Sacha Date: Tue, 25 Dec 2012 09:13:50 +1000 Subject: [PATCH 01/89] Update Qt project/Symbian --- Common/MemoryUtil.cpp | 6 +++++- Qt/Core.pro | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Common/MemoryUtil.cpp b/Common/MemoryUtil.cpp index 282ffe2ee4..f4ff4da1a5 100644 --- a/Common/MemoryUtil.cpp +++ b/Common/MemoryUtil.cpp @@ -115,7 +115,11 @@ void* AllocateMemoryPages(size_t size) #ifdef _WIN32 void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE); #else - void* ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + void* ptr = mmap(0, size, PROT_READ | PROT_WRITE, +#ifndef __SYMBIAN32__ + MAP_ANON | +#endif + MAP_PRIVATE, -1, 0); #endif // printf("Mapped memory at %p (size %ld)\n", ptr, diff --git a/Qt/Core.pro b/Qt/Core.pro index 6c2cada922..d3fadba4bc 100755 --- a/Qt/Core.pro +++ b/Qt/Core.pro @@ -136,6 +136,8 @@ SOURCES += ../Core/CPU.cpp \ # Core ../GPU/GLES/TransformPipeline.cpp \ ../GPU/GLES/VertexDecoder.cpp \ ../GPU/GLES/VertexShaderGenerator.cpp \ + ../GPU/GeDisasm.cpp \ + ../GPU/GPUCommon.cpp \ ../GPU/GPUState.cpp \ ../GPU/Math3D.cpp \ ../GPU/Null/NullGpu.cpp \ # Kirk @@ -245,6 +247,8 @@ HEADERS += ../Core/CPU.h \ ../GPU/GLES/VertexDecoder.h \ ../GPU/GLES/VertexShaderGenerator.h \ ../GPU/GPUInterface.h \ + ../GPU/GeDisasm.h \ + ../GPU/GPUCommon.h \ ../GPU/GPUState.h \ ../GPU/Math3D.h \ ../GPU/Null/NullGpu.h \ From 14ef840dd3057dc2df925c5aba6d8341bedb39fd Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 28 Dec 2012 17:23:05 -0800 Subject: [PATCH 02/89] Add a command line option to load a state. For debugging. --- Core/SaveState.cpp | 8 +++++++- Windows/main.cpp | 8 ++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index aa74d0cebe..11f5945c10 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -87,7 +87,7 @@ namespace SaveState // Don't actually run it until next CoreTiming::Advance(). // It's possible there might be a duplicate but it won't hurt us. - if (Core_IsStepping()) + if (Core_IsStepping() && __KernelIsRunning()) { // Warning: this may run on a different thread. Process(0, 0); @@ -122,6 +122,12 @@ namespace SaveState void Process(u64 userdata, int cyclesLate) { + if (!__KernelIsRunning()) + { + ERROR_LOG(COMMON, "Savestate failure: Unable to load without kernel, this should never happen."); + return; + } + std::vector operations = Flush(); SaveStart state; diff --git a/Windows/main.cpp b/Windows/main.cpp index d2f9b186ac..75d1ec9e92 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -21,6 +21,7 @@ #include "file/zip_read.h" #include "../Core/Config.h" +#include "../Core/SaveState.h" #include "EmuThread.h" #include "LogManager.h" @@ -53,6 +54,7 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin const char *fileToStart = NULL; const char *fileToLog = NULL; + const char *stateToLoad = NULL; bool hideLog = true; bool autoRun = true; @@ -93,6 +95,10 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin fileToLog = __argv[++i]; if (!strncmp(__argv[i], "--log=", strlen("--log=")) && strlen(__argv[i]) > strlen("--log=")) fileToLog = __argv[i] + strlen("--log="); + if (!strcmp(__argv[i], "--state") && i < __argc - 1) + stateToLoad = __argv[++i]; + if (!strncmp(__argv[i], "--state=", strlen("--state=")) && strlen(__argv[i]) > strlen("--state=")) + stateToLoad = __argv[i] + strlen("--state="); break; } } @@ -158,6 +164,8 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin if (autoRun) MainWindow::SetNextState(CORE_RUNNING); + if (fileToStart != NULL && stateToLoad != NULL) + SaveState::Load(stateToLoad); //so.. we're at the message pump of the GUI thread MSG msg; From da551d71c3f7e911b612ab8809417d3b0a1fd955 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 28 Dec 2012 17:24:14 -0800 Subject: [PATCH 03/89] Disable load/save while no iso loaded. --- Windows/WndMainWindow.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Windows/WndMainWindow.cpp b/Windows/WndMainWindow.cpp index 5237026b8b..aa8347af09 100644 --- a/Windows/WndMainWindow.cpp +++ b/Windows/WndMainWindow.cpp @@ -656,6 +656,8 @@ namespace MainWindow enable = g_State.bEmuThreadStarted ? MF_GRAYED : MF_ENABLED; EnableMenuItem(menu,ID_FILE_LOAD,enable); + EnableMenuItem(menu,ID_FILE_SAVESTATE,!enable); + EnableMenuItem(menu,ID_FILE_LOADSTATE,!enable); EnableMenuItem(menu,ID_CPU_DYNAREC,enable); EnableMenuItem(menu,ID_CPU_INTERPRETER,enable); EnableMenuItem(menu,ID_CPU_FASTINTERPRETER,enable); From b94bcad28837d6cc758875379a13acacee57acc4 Mon Sep 17 00:00:00 2001 From: raven02 Date: Sat, 29 Dec 2012 09:02:47 +0800 Subject: [PATCH 04/89] Fall back to original filter logic when filter option is off --- GPU/GLES/TextureCache.cpp | 8 ++------ Windows/WndMainWindow.cpp | 5 +++++ Windows/ppsspp.rc | Bin 29384 -> 13304 bytes Windows/resource.h | 1 + 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/GPU/GLES/TextureCache.cpp b/GPU/GLES/TextureCache.cpp index 3e13c466e3..6322d9a62c 100644 --- a/GPU/GLES/TextureCache.cpp +++ b/GPU/GLES/TextureCache.cpp @@ -428,16 +428,12 @@ void UpdateSamplingParams() int tClamp = (gstate.texwrap>>8) & 1; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, sClamp ? GL_CLAMP_TO_EDGE : GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, tClamp ? GL_CLAMP_TO_EDGE : GL_REPEAT); - // Tested mag/minFilt only work in either one case that can allow GL_LINEAR to be enable - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilt ? GL_LINEAR : GL_NEAREST); - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilt ? GL_LINEAR : GL_NEAREST); - // User define linear filtering if ( g_Config.bLinearFiltering ) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilt ? GL_LINEAR : GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilt ? GL_LINEAR : GL_NEAREST); } } diff --git a/Windows/WndMainWindow.cpp b/Windows/WndMainWindow.cpp index 5237026b8b..fa045c4286 100644 --- a/Windows/WndMainWindow.cpp +++ b/Windows/WndMainWindow.cpp @@ -503,6 +503,10 @@ namespace MainWindow g_Config.bFastMemory = !g_Config.bFastMemory; UpdateMenus(); break; + case ID_OPTIONS_LINEARFILTERING: + g_Config.bLinearFiltering = !g_Config.bLinearFiltering; + UpdateMenus(); + break; ////////////////////////////////////////////////////////////////////////// @@ -648,6 +652,7 @@ namespace MainWindow CHECKITEM(ID_OPTIONS_WIREFRAME, g_Config.bDrawWireframe); CHECKITEM(ID_OPTIONS_HARDWARETRANSFORM, g_Config.bHardwareTransform); CHECKITEM(ID_OPTIONS_FASTMEMORY, g_Config.bFastMemory); + CHECKITEM(ID_OPTIONS_LINEARFILTERING, g_Config.bLinearFiltering); UINT enable = !Core_IsStepping() ? MF_GRAYED : MF_ENABLED; EnableMenuItem(menu,ID_EMULATION_RUN, g_State.bEmuThreadStarted ? enable : MF_GRAYED); diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index e9561bdac4468508cfa78c949648e089abb2f193..aeb975be72f2ea79989ec02bec57e8009212c673 100644 GIT binary patch literal 13304 zcmd5@>vE&WlK#DZiaP2Dg*%3E>*m|}hoB^LjDP@Sw>Kt2fh{Z(Er9}1yS*{5vrlqf zY`?4mp$n4x%yI9oXWBNXGApwxFJESrzkFe%=qXLI`E+x*a1-QmRI5p6ZR5Zm6a`4! zq5pereCu{QC!YUca;AF|kNX4L^4XvCFfhJy-Fxuxbni_Z+Zj9ZS50+%!?xrD28_5h zmJj}oq1_H#b;M8jSIHHm{Od&3H17BV!{h}!yz_0_yf-Y}zCS5BHZ*74I1wUTDXcN_ znD-LS=S-i^8bV|e{73tw&xeL}!tiDK{HxCzTAu#Bp;ShrTqqr--BGT@Ag&v}7)Jwi z-X9Mqnmx9BrQ5==?lq0%-el}J+|^W%Lm51(W8c2 zk}8*DH5;+2Z+~TE6+_#%4Om34OM@<2%H@Tk^}UJi+72w#G7XR10(*Y9HVHiVYTtt( zVr~td17m?PuChE?wB_W|_3jLQuaK3_^(a%b#a$G>Hk7pmNzMf`VKQwP@b#tAEw**& z+GB@gCEH?^1yF!gpgoMe)lqtvM+9;Ckd%;8xZy0y@-Q{={jeO$6}AX`JH6{|#!@wt z4}6kYX?Sm$A3SPFoTtgW+i57i2ImmofZbLuy2|Ahc1bWHA<9)Bj4h2qi4d%4-r^zxG}t;*M$q-8J^Kc^g6ybo0i+WgIh@ryc_$To@izW zNnYAH;g&9=rrNj1Le!nO*=@BI*1qT-h?^r@S4|NFA=I%rx+QuU0)-w$P_5#k`k1Wp z_akF#BQowp5Bru>wr`;%1(>#SzIJ~DmJ25^CXVBIj?4uVok?wyRba$K>5 zB1x0eV23-GinNq6EGNsiG@8BS?DXj~dwgRzVVp+anEN)J{qw)mDeJV_u$GOu4L)6L z#Cf*}-322RNdWnJ8ZLtLTgHMkWXm*JhH3uBl4q8`gi%Vld>KCF(f5!guYfh#*&nh0 z60&fyng@B3vM6KE_z_N5PeC3fG4g*9Pm$KYhx25)2;-bBSLrgz!i**H{7rls3avW16JjKepqKnbLj-j#Am^JA;FcGGh_ z{g#M6Ewd#SgPlI7VHg9aeBM^#O1Yq5utWb}^XQSN{}Bf9@AG7}WWyk$RXE)c?6X+Q z5q6KM(|MS((=EC8Cb~M`pGcifqhi~h(h$FA+c_VC^~zORJMoB*Z1-Ug`t*7V>s(zP zaN&=HK6Nl>6fTnV4LBTG;2_-TwIocd1w6wfPj<9dE`bK>5KozQfh^9Ii!$qOz?<#h zF4I@xmRPn?0Ya@g@4i5n^yQ*Fc7)oPBq8eLX`oNhs9sl8GWfU zdBp`19uTqso4aOzC{3QXm2Ph%Np2ztEr_2&X=|#baT6POQH@?NJ0XkRz|%q6Wj&xCI?3P#p{rrnTXANzo@dEVeD)Rn=!{5Pvux(%m0Mv5{t3JGt7sW33jG<*% z16vflsN=Vq42E@Q-*WwAI5u={8Wu`Wy`rc}$*NFRid_>PSq%{J448L>(%-NE0mbL^ z)+J0@zV5YTdZiCgZTVtejBZ!s`!)*2QAyD4N_0g8H@5qq1%V7jJ1>iRK-d_4L_(K1 z^=HMdX4{gxb1g$QvE7inR}J5MTdQN|sv3;4s8mpvCB%1I@it-)z1`AAChQ}+Yzf`# z$+)@CymNK2&wL#fer|^=!M7%DpG(#>=})NHE4mO=R}cy9nW#Dr3$ZmF>Y=rzZ7*Q2 zD0^uE>EEX?o}!C|2GF`SS6ctC=`$HmNi3WWQ_}D3HOgPuJb4YX9D2&2O3BZO^}d)vlHZH}@~j^m@TiL%VL(4j7RKQzgDu*V(MRe?26 z)~^~(GYO{5%h788BOmk{Tk}zU#y1Ch0czNCaHksVsds#5a5WjpKws6Qy!j(SduKft z|7!R`H;NTBv|K4JDrD4;?<|+QiXr{=?lQPz*^J$uz3Bv~mNCBF+9hz*vB&pU`Is(l zGt9!AxS_E|8dbZ1o+6ieZ3%FU8?{lx6jd|6OLpiyPpHS_Ixffeec>8SZ%(ZY6t;ta zdS|Sb$3XS`clhXUF&Y?8)x7$HrMg^Gn0CW8f-0oP&K~LEJ+`_NvE6eeIof4XGrV!w?0vxk-)FkQ%C@I&V^~i$yF5N1KEa zq)=sCw^s-&)ThXf?^e@KX0v(71}kJY4;_t=oQwKlWZt$oW5FrR*fh~`=DgO$usWg> zC8=zXR*@>o!W5ysQbB4o7 zc`mov5TI9GST&sXfHdT;tk~4ksdPStt>P>vTm1~tuC{rS56c~{lj%N6!)ID+b{hUb z3o@d{VK7GvYjfZ34VTN4Fmh)4s^W6fdr4jydGt&~c>ta02|b2QdTLDz2NKOY#1zfj z7v`AfNQ+|4_K(7Vi?~@@g*2-6*L|*ylC)Ej?%1Rx?HnWRmZaSswS*~mkCFCD(q0{D zuZHy4GBk}@oWK&%k)-Ap)aizs4qTjD_q^``i|lX0QJutb0F!O_b(j}CMJ*_} zk=*oeqbMkGZ5>Gb|BY~e0b=%E(L&B%*eU%I#{Vv0_U`yDUiR*B`sv+NR{@F_|A%;4 z06q#t-T~0O2p8W)SDGT$A=oVKJBnFTWaovn>7rF!9HolHTocoe+O>xBqO#FP!LVeh z+0KJ#`tAEkqp7bJ%e51f6#97NtlfZgDWER4JjfQu{Z~lQ45m{$RFS$#ZE$PAc__N+ zHIfKA6t8)@!YLHW*3;%o_@l@R8ypPF^WCvH_`KmY;jB@^NXmVb*I!z3AbP6EU&6Em zZQ`oP1dtxLAGli+nE-?V_r&?XC{ZZ=ZLJc}xT77WE@00iBJsCn673NC_HbzOKH~4K zLx;XK>)ae9bF>)PBf!Pe%huEbT-LDf`+yYM%|7K(+mkt2q5}Y+3`O+z<`*a(cosEp zO)_p&Zc%^@d00Y*T6(D}@K8u-*2qR&>12O$i==vNiZq0{_@Eph@PTBDeTU0{agNkI$B=EQE*8F{ZI7Zh3z(WYrpp?c;RK@&X_bTQKNhBlMePt zJya?h@W6X=9w;^6Cv-RGq|-yX1Mt4AcefKXX@n&+Ewd9g*eSEwJPyTs}2x^b~nnAZ`}UXYx)>$yQ# zRo{nb8u!x9#cq!+>TGQct=~GD2iN4bCR(>vHmKJtA!?^z67%kGH3{%g#Jf9OD1?hr zGno!B>EMkX#9<~Q{fZZi?g`+(6Xv+K4)D15o(2z0b?A*$@0M=KUYc~JnT|r`o!1k= zPYj`t@o6~E!tJ*$dP`?W^0n<@WY3fjbli(a3=xcQzqxu-!GgYNYqzZ7<ds+7*N< z#05HHyMAD&+GkvyYhCK$=PwtdxLYU;rheo*3tht3@@HX?cR_m08jD32 z{YqRGlv@tlZz0R!s**g`{Nr#_V8#ST zvEK+3ma~=;iIC9n-DUZQFb|#$V0!3q$ioc)%{cd{{b*6V?h7_ literal 29384 zcmeI5>24dz5y$822FN=wG$42puh*93E8lGDuwq>hX?q!VlV|AwQhw8Jgz0kF@ z>Pz*yI?}H}^+$br)j{>XI??x3*FWp{PS;L#aSHlJk6Uo!gC+Od$j$y+O3AwsCr(lR2$V!wO{R3tGc?P z^X+Q0dZjBv{oSgb=*p(fX~kM<_Wd=q`%ch*71Z^fzX(>K{4i&~)&{*Zf(^ks2vCj$ z_ej47y82yp_X1L|bv-{$%bsxkUNrnH>KTXBx!~+#G|(Ij{vo5}yXvM!zgGQlPQjt5 z^<1aBn1(;NFH7~HGY^~Sc|d#*Qta8p;eb@jQ9>$={%xZ=-^^wwit zy`_6YJ@;hn6UI58!Z;7AV~w^a{{0vr+82kv4l;35)LX3X>1z-;o~}0)9m<~YeHiHY zQKRvz9QnepD}g2(!qsDaw}bc~qKjAb_dw6XyD84^R6n2VkSBs^J@iYDz4OneAOLINUbe} z(a`Qv_2{Axu)D8kcJ)~e`T-7vhu{{w`&jqE_fy>&=o#?7nLSar5%%`Bo&+04U+l%6 z#y~GA-k{DAG9t4K)3cV8zRStnYE~_}|M9=KZEd%LWL5^O#84mn?FkQXy zE%mmdUN{DN*-}@$QU9x&O`>>d*EC;~Vic^U=%kqwfSw!juBKLy*sOv`}0d?;()%UcwAwIwt#^Q6#y~3y?ZT^KHy%_r9FSzse z+Ghi4FF7B_xP@Ch%M8U?raLnf}?NC0J)@1f&5f36d!~#wQ(V4Dt_FhNg1dImj z@HxOvJdL-Qza8qT$IE!;t*##iAGoKtzJ~bFsoJ|;{iyR%c&Df5j>XwW>H`Z;3s{|= z+O=Oq;l8LX?jP#fiOzuZwa&l~u;OPQ>E0)`1untyC%tv5zeN3r-~q#lo&w|k?qPV6 zk#hA!Pw?g&J>S#YyhjhfMSH-=a|b%o4{iRUdtY=U#ui&R(p{bcr@UdKzuihhxA#s( z3Ms7-2^)Z95H-h;fEnJh*x0wNP~Dd-nr55@ zs=teK4n-%2=+D9!6#P!t;W*~A>$-Ay!DHx@5_ZuuPWvsLA=AW}-|0>0&*&KExVPJ| z|1kKgaOy1M1dewaMK0UK*O5K0pG}O|Sg-h&b=_C?F^GX-_xI!_wD}jy8WS@tbnruQ z*|h$}^^Ni|3+ooW+Y%j)#aE|6kC8R8ITW~m;E@>Dn>V6ITng+B88@(z)v{J^uEm?&@^b2tuU8h zX8J@L`g7pSlkmJnP@FTEYvAeb=(#lJ8s`Ktl3*4DD~E1dj;`U(}~AV_l+P77el4`!GO@ zu0XOM>O=b$3BIZ*SlLPu0bm~9btY`{Uo`7IeWtZjmp>1#&tM~GcbV-DG&8_s!9VTE zw@2!}=zO-h@8w$^^Z`~dhb_)jUj#kyJVZGx>t+@R&UzT+IG2g8R;bPuZr9M$%(aoZ z=`7JKbNzej1N(r~mFM~G5u`z&FVz&OJ|(M7ew@5Da?Q9({gh?K<4$c}9dj%5LYAd7 zENU=K)ad$pb-RJ@$T^dvY|qR(#(o{SYPVCV#dF5Ik-g_Z`F8mP!WyGBa;3WQS!a&FSTBBpKkKA^|)%z zzy7XczaCY;3JR1*I-Ul2iFwx2p)S(^nw2Op?&)dh%iO-)y5%bC{F7(m9PUZHfS$?o zOOq*<#wcc|)_Cj_)yTc&E~5ZX_cJO?9tHB5`mnQ)WSr!eDKUQB&>cXrH-A1iaDGJYm;D)XvbF5?K|*$vqdV((V>XgI_+m8w^pmIXQH`&+WH8zDM+ zashWb2C~7#PERy`>TSt|^yJqP^C!wpMgd)%&K5kIfCo&5f%;!EBRp%_1~5#0vgKV~ zE8a`~fjZ`x2O(2pJv%-v`$C+8YFzRYcArQ)t$S|7ptbx2^~~haxqGamRWt)}Js0QF zQaZNf_UiBS!-&WMFtXd{BQa0Z`}S&)`n&bt)A#LoyW7&UdoG??pTB4DOrEOV^LUx+ zR*8JQr74w{>j`O;pgO*9N)qs!UrQQ~L_P8;mcNQ?0?vYFpp9R%8hqta>cK4rKx~pM zv5n!sy&jxc`HAT1ROiSS&9kQp1UxXRsqc!`e$M^!3?;4Drp9Yc+Kk+qX*1Uu<#+wA z_dQBVnIBWqgeOul9_@0OAjT!_h+4G*s-uMVh$9m6HGcv2`(sLO<^BAr z7HL7bo_XazYX1e<2WCvY3rpN)KW&6~LcVgx?IqEl-3vR~jem{)ZV~2(#cjf@u${G$ zl6R%Z-_6nZ{Eli<{1xVTuR4waD#LRJK?0ajvq~6T=CEvbgvHhxcEcZ8^0Y38ifpUQ zF;34R*s4L$!~-_OtD?NNB!#3+ju+&eu^QSeITZ%!+p~DSqk!3ifKTKYU*SlY9!hti z!SIUB!g_72>l_;$D^a%Lj)~Bp$ywg~9hrpsr$i1!brnZ=Tx?${IjUOh%nnFW% z2n|5>KG0#4)-zgrTTQP7d3h>qQPuo49PyV&0fWen)%zY#1>4hLhgO6=vq!e>d0SMb zHjRp$ln*Dv=JuHxUn*NvN2Zn&J&B)*EqCo{)u7&fJdWc$W#6X^898I<8+oxiT&&?G=1G3fD~#iO$l{O0-K_p7;>i7r zy2Sc=l4zBEPGt3GME!;x={vizotJT*YNWfGOLfI~9kRs+ zWL7yi4x03OJ7kMu9;tEluT<+Sv16H^k zNk7f+7f|u*ITF^=d{(P}3b~}O8sAsN$;chx~fvw3J1*K_p*L0s+BHcxR~8AlMa`>EcD6p3ft@1AAo9`(MS@qD0S#Qyz1 zl=EQ#JkkOdoxCR5-?NbEym@g2uj4voM}{GS+P+uLFvz|6;!lItukV$UKVcH|zn&Y3 zkzCh_REGIEI4aNg;(O#a@KKKyGf&r(xXvxV?{~eYH1?lb1!g*UYB5eQZcbq>nhm7Y zE%A-*A+RrdXFEGE!--LXuJeg`Y{Nhnj`gBxy+Ajgq&yPpE_XG{j8)0d$g%0i5>~1B`J(PrV@T5H1I6*$y4FmR?S+4#!c}tD{Fsl%;P3O1J5#7B6kt@CctOt zKD+1!TS}Wa)0`f*6sz5^H;;r_o+x^e#B91{IZGq63=#QBFpP)XZ3Gr2CevcO&Djn+ zF@NZ@_%dgfAOR;MNf$Jq1)4nO_9kHEwN{I=h8hkXpDipw0}Si>Fnf4%K67{`=zM>R z?pRt=|3v>Rx&U0P4tXodDC5Ru&b{T7yNCqZ{#oo*0bI7~;Auyy&BJ$Tgd~k9vF0Bw zWc4K_T~xwvo`-?&@Ls6l$Y*Dcjgkf`+08uq<#FXErb{rTR?{phvq)@@+0|||p9ja! z#Hki3{t%*cQJXeL;Fz&vX*{OaZD*@)up`w_lS~^DOl=?0!U)GCTUvqv%93vbpY{D_ zQkdH8sKY@OA+}~-Te_fp-+Z|C(fDpV`)bkR4SvTX_|uFNT~6NMazv1EaCiIK@E#;o&>@w0 zJd)Xc-a+uVeD&cZSxup^^Kr0{r65m|dj?Tn;~ALdJKtRWD&KbK{D|!uDUwERn)OFy zt?)hlK1aS((oORzw>rKB_F4WcIH-L-k?eoaeC3UftiN^`t`aZvwVh&%mZ+qEs}E6A zyi?yBCw-1{IF5Qn-?f$eChyuFu6SOtcFw$l@|>x!cG~qt%*3!8AXymlSjfF+&Rt@$ z_fU}aWUtO^MABXUc+Ph^^EEt-$LZUbA2S_1mOc0Wy&XT!56|k9@T8hO*2l2I9GK>Z zXKfC6pcwg5;JPe$>NN(Ac{`eBO!+6pk9&uadh_GQb`8p*h`*Zfn3cB7B2wd&vUlc% z=Y=GJnFl)xL@45!!Gj#tD`sQuU;1Vfo=MW=y|ey2_8HH{_il6B`di(4|3+MHqh=qZ z*jqfaeq$x6*ExBfm-W8!>5|lxMjiXLy?fFY?7ZHu*Luy@ulLiJt!vj^&1^UOrdnMJ zS>QPGCbsjH)I3?jLxg8?9@wxk2_AC4mkH10>~A|fWPC3Zp2<1ic6iA1ULHIyHLOr~ z8m7lGJndCF_12nvHJOWEcHrtL%T!IfT-AGKG|k?p<7&qe)nBFd%UCK^f!W(lcuLs# zZF}l3f-mX2?$v!s_HN!6UCjE~jyP5aO~ed}rFV!ibKSf)r+fYkYx8ZF9(G>vHP+Nq zv+t_Krn|i1t*?or_>UL-hXy=P_Up6%3h+R8fF$4N058=mdUH5qOWuONkH<}2>E!3{ zT=ZuZcFZ^OH`u+<+Fm|?mTEy;jl&ML)E(G;Z!6xnEM)nqvj0xq>W=(5Fv1QQWD=PB z9H>uQi?pF%RM<@u^~qahpQSrmx6kp7{^l*YhAPA7cl{W1QMSJ~`xbh<+vA^o;V4!{ zP$yB|*|H4Bq@MV%CMU|UZJ)>J%v$&54MWXw`>=w+w;>B=l=dF-V?Hv+J{584e+}{# zFX*0poYRcPThHa%M}zFaVd>v#T4%hrdct;Gtz!#1b;rb}Fkm~PdaMUL+xiHHxOs=l z#zCklV9yqI1o|%Q-h$TmoiQg-Z8iw4CiR^lCYoS-;5v+t&!fv!0kBV*}w`VK3NOcFdh-Bs+nJ*~#4~=X~NY`dCu=x~}EKq^GDkH?5)nr z+tFgXoHnoIdhSJ_x#MgWy_xF(<0kUEw#RWQ`&cj2sz@nZ4VR}<6`_r1+~+%A%;_rM zcIfx3;?Sd{s%=vf$_8w@{x*Ou=&r%$xcDM^1G=qHT$$`Tt<^ z>)sB2>xNpQHlO)8Sf?hC{TtFxU;YbmMyex-(Yf`aGRn9;r`KhTizxDTm?@^vU`5si z1=g!B!#*KKpyia%+`zVP>pu;g&%co|=j zIBT8RRr2+GZ99+q(Y)13|AP-X$oJ)%4}z$P$bs(wZKOf>7FX;<6r~iA=_9jVtxyljE-ZnTG&)L4ueDi-jHt9`E{{c|G#peJ3 diff --git a/Windows/resource.h b/Windows/resource.h index 134447f2a5..af56ef8446 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -247,6 +247,7 @@ #define ID_OPTIONS_HARDWARETRANSFORM 40124 #define ID_OPTIONS_FASTMEMORY 40125 #define IDC_STEPHLE 40126 +#define ID_OPTIONS_LINEARFILTERING 40127 // Next default values for new objects // From 6eec4f5d7f42f5f615f65681d5b7d7fc81cf5582 Mon Sep 17 00:00:00 2001 From: Florent Castelli Date: Fri, 28 Dec 2012 21:58:00 +0100 Subject: [PATCH 05/89] Move display list management to common GPU class --- CMakeLists.txt | 2 + Core/HLE/sceGe.cpp | 22 ++------ GPU/CMakeLists.txt | 1 + GPU/GLES/DisplayListInterpreter.cpp | 87 +++++++++++------------------ GPU/GLES/DisplayListInterpreter.h | 22 ++------ GPU/GPU.vcxproj | 4 +- GPU/GPU.vcxproj.filters | 8 +++ GPU/GPUCommon.cpp | 49 ++++++++++++++++ GPU/GPUCommon.h | 24 ++++++++ GPU/GPUInterface.h | 24 +++++++- GPU/GPUState.cpp | 3 +- GPU/Null/NullGpu.cpp | 85 +++++++--------------------- GPU/Null/NullGpu.h | 8 +-- 13 files changed, 176 insertions(+), 163 deletions(-) create mode 100644 GPU/GPUCommon.cpp create mode 100644 GPU/GPUCommon.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fd1b01c88..4a44d5bef0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -806,6 +806,8 @@ add_library(GPU OBJECT GPU/GPUInterface.h GPU/GeDisasm.cpp GPU/GeDisasm.h + GPU/GPUCommon.cpp + GPU/GPUCommon.h GPU/GPUState.cpp GPU/GPUState.h GPU/Math3D.cpp diff --git a/Core/HLE/sceGe.cpp b/Core/HLE/sceGe.cpp index 023ac3aaa0..7331d99d35 100644 --- a/Core/HLE/sceGe.cpp +++ b/Core/HLE/sceGe.cpp @@ -25,17 +25,12 @@ #include "../GPU/GPUState.h" #include "../GPU/GPUInterface.h" -// TODO: This doesn't really belong here -static int state; - void __GeInit() { - state = 0; } void __GeDoState(PointerWrap &p) { - p.Do(state); p.Do(gstate); p.Do(gstate_c); @@ -74,12 +69,7 @@ u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, u32 callbackId, listAddress, stallAddress, callbackId, optParamAddr); //if (!stallAddress) // stallAddress = listAddress; - u32 listID = gpu->EnqueueList(listAddress, stallAddress); - // HACKY - if (listID) - state = SCE_GE_LIST_STALLING; - else - state = SCE_GE_LIST_COMPLETED; + u32 listID = gpu->EnqueueList(listAddress, stallAddress, false); DEBUG_LOG(HLE, "List %i enqueued.", listID); //return display list ID @@ -94,12 +84,7 @@ u32 sceGeListEnQueueHead(u32 listAddress, u32 stallAddress, u32 callbackId, listAddress, stallAddress, callbackId, optParamAddr); //if (!stallAddress) // stallAddress = listAddress; - u32 listID = gpu->EnqueueList(listAddress, stallAddress); - // HACKY - if (listID) - state = SCE_GE_LIST_STALLING; - else - state = SCE_GE_LIST_COMPLETED; + u32 listID = gpu->EnqueueList(listAddress, stallAddress, true); DEBUG_LOG(HLE, "List %i enqueued.", listID); //return display list ID @@ -117,6 +102,9 @@ void sceGeListUpdateStallAddr(u32 displayListID, u32 stallAddress) int sceGeListSync(u32 displayListID, u32 mode) //0 : wait for completion 1:check and return { DEBUG_LOG(HLE, "sceGeListSync(dlid=%08x, mode=%08x)", displayListID, mode); + if(mode == 1) { + return gpu->listStatus(displayListID); + } return 0; } diff --git a/GPU/CMakeLists.txt b/GPU/CMakeLists.txt index ad56972231..19beca69da 100644 --- a/GPU/CMakeLists.txt +++ b/GPU/CMakeLists.txt @@ -1,4 +1,5 @@ set(SRCS + GPUCommon.cpp GPUState.cpp Math3D.cpp GLES/DisplayListInterpreter.cpp diff --git a/GPU/GLES/DisplayListInterpreter.cpp b/GPU/GLES/DisplayListInterpreter.cpp index af4966ee18..b6a0e3ec85 100644 --- a/GPU/GLES/DisplayListInterpreter.cpp +++ b/GPU/GLES/DisplayListInterpreter.cpp @@ -162,9 +162,9 @@ GLES_GPU::GLES_GPU(int renderWidth, int renderHeight) displayFramebufPtr_(0), renderWidth_(renderWidth), renderHeight_(renderHeight), - dlIdGenerator(1), dumpThisFrame_(false), - dumpNextFrame_(false) { + dumpNextFrame_(false) +{ renderWidthFactor_ = (float)renderWidth / 480.0f; renderHeightFactor_ = (float)renderHeight / 272.0f; shaderManager_ = new ShaderManager(); @@ -386,16 +386,15 @@ void GLES_GPU::EndDebugDraw() { // Render queue -bool GLES_GPU::ProcessDLQueue() { - std::vector::iterator iter = dlQueue.begin(); - while (!(iter == dlQueue.end())) { +bool GLES_GPU::ProcessDLQueue() +{ + DisplayListQueue::iterator iter = dlQueue.begin(); + while (!(iter == dlQueue.end())) + { DisplayList &l = *iter; - dcontext.pc = l.listpc; - dcontext.stallAddr = l.stall; -// //DEBUG_LOG(G3D,"Okay, starting DL execution at %08 - stall = %08x", context.pc, stallAddr); - if (!InterpretList()) { - l.listpc = dcontext.pc; - l.stall = dcontext.stallAddr; +// DEBUG_LOG(G3D,"Okay, starting DL execution at %08 - stall = %08x", context.pc, stallAddr); + if (!InterpretList(l)) + { return false; } else { //At the end, we can remove it from the queue and continue @@ -407,32 +406,8 @@ bool GLES_GPU::ProcessDLQueue() { return true; //no more lists! } -u32 GLES_GPU::EnqueueList(u32 listpc, u32 stall) { - DisplayList dl; - dl.id = dlIdGenerator++; - dl.listpc = listpc & 0xFFFFFFF; - dl.stall = stall & 0xFFFFFFF; - dlQueue.push_back(dl); - if (!ProcessDLQueue()) - return dl.id; - else - return 0; -} - -void GLES_GPU::UpdateStall(int listid, u32 newstall) { - // this needs improvement.... - for (std::vector::iterator iter = dlQueue.begin(); iter != dlQueue.end(); iter++) - { - DisplayList &l = *iter; - if (l.id == listid) - { - l.stall = newstall & 0xFFFFFFF; - } - } - ProcessDLQueue(); -} - -void GLES_GPU::DrawSync(int mode) { +void GLES_GPU::DrawSync(int mode) +{ transformDraw_.Flush(); } @@ -547,7 +522,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { { u32 target = (((gstate.base & 0x00FF0000) << 8) | (op & 0xFFFFFC)) & 0x0FFFFFFF; if (Memory::IsValidAddress(target)) { - dcontext.pc = target - 4; // pc will be increased after we return, counteract that + currentList->pc = target - 4; // pc will be increased after we return, counteract that } else { ERROR_LOG(G3D, "JUMP to illegal address %08x - ignoring??", target); } @@ -556,21 +531,21 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { case GE_CMD_CALL: { - u32 retval = dcontext.pc + 4; + u32 retval = currentList->pc + 4; if (stackptr == ARRAY_SIZE(stack)) { ERROR_LOG(G3D, "CALL: Stack full!"); } else { stack[stackptr++] = retval; u32 target = (((gstate.base & 0x00FF0000) << 8) | (op & 0xFFFFFC)) & 0xFFFFFFF; - dcontext.pc = target - 4; // pc will be increased after we return, counteract that + currentList->pc = target - 4; // pc will be increased after we return, counteract that } } break; case GE_CMD_RET: { - u32 target = (dcontext.pc & 0xF0000000) | (stack[--stackptr] & 0x0FFFFFFF); - dcontext.pc = target - 4; + u32 target = (currentList->pc & 0xF0000000) | (stack[--stackptr] & 0x0FFFFFFF); + currentList->pc = target - 4; } break; @@ -590,6 +565,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { switch (prev >> 24) { case GE_CMD_SIGNAL: { + currentList->status = PSP_GE_LIST_END_REACHED; // TODO: see http://code.google.com/p/jpcsp/source/detail?r=2935# int behaviour = (prev >> 16) & 0xFF; int signal = prev & 0xFFFF; @@ -624,6 +600,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { } break; case GE_CMD_FINISH: + currentList->status = PSP_GE_LIST_DONE; finished = true; break; default: @@ -641,7 +618,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { break; case GE_CMD_ORIGIN: - gstate.offsetAddr = dcontext.pc & 0xFFFFFF; + gstate.offsetAddr = currentList->pc & 0xFFFFFF; break; case GE_CMD_VERTEXTYPE: @@ -1095,13 +1072,14 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { break; default: - DEBUG_LOG(G3D,"DL Unknown: %08x @ %08x", op, dcontext.pc); + DEBUG_LOG(G3D,"DL Unknown: %08x @ %08x", op, currentList->pc); break; } } -bool GLES_GPU::InterpretList() +bool GLES_GPU::InterpretList(DisplayList &list) { + currentList = &list; // Reset stackptr for safety stackptr = 0; u32 op = 0; @@ -1109,14 +1087,17 @@ bool GLES_GPU::InterpretList() finished = false; while (!finished) { - if (!Memory::IsValidAddress(dcontext.pc)) { - ERROR_LOG(G3D, "DL PC = %08x WTF!!!!", dcontext.pc); + list.status = PSP_GE_LIST_DRAWING; + if (!Memory::IsValidAddress(list.pc)) { + ERROR_LOG(G3D, "DL PC = %08x WTF!!!!", list.pc); return true; } - if (dcontext.pc == dcontext.stallAddr) + if (list.pc == list.stall) + { + list.status = PSP_GE_LIST_STALL_REACHED; return false; - - op = Memory::ReadUnchecked_U32(dcontext.pc); //read from memory + } + op = Memory::ReadUnchecked_U32(list.pc); //read from memory u32 cmd = op >> 24; u32 diff = op ^ gstate.cmdmem[cmd]; if (flushBeforeCommand_[cmd] == 1 || (diff && flushBeforeCommand_[cmd] == 2)) @@ -1124,15 +1105,15 @@ bool GLES_GPU::InterpretList() // TODO: Add a compiler flag to remove stuff like this at very-final build time. if (dumpThisFrame_) { char temp[256]; - GeDisassembleOp(dcontext.pc, op, prev, temp); - NOTICE_LOG(G3D, "%08x: %s", dcontext.pc, temp); + GeDisassembleOp(list.pc, op, prev, temp); + NOTICE_LOG(G3D, "%08x: %s", list.pc, temp); } gstate.cmdmem[cmd] = op; ExecuteOp(op, diff); - dcontext.pc += 4; + list.pc += 4; prev = op; } return true; diff --git a/GPU/GLES/DisplayListInterpreter.h b/GPU/GLES/DisplayListInterpreter.h index ae22e56188..49e20eac88 100644 --- a/GPU/GLES/DisplayListInterpreter.h +++ b/GPU/GLES/DisplayListInterpreter.h @@ -18,9 +18,9 @@ #pragma once #include -#include +#include -#include "../GPUInterface.h" +#include "../GPUCommon.h" #include "Framebuffer.h" #include "VertexDecoder.h" #include "TransformPipeline.h" @@ -29,16 +29,14 @@ class ShaderManager; class LinkedShader; -class GLES_GPU : public GPUInterface +class GLES_GPU : public GPUCommon { public: GLES_GPU(int renderWidth, int renderHeight); ~GLES_GPU(); virtual void InitClear(); - virtual u32 EnqueueList(u32 listpc, u32 stall); - virtual void UpdateStall(int listid, u32 newstall); virtual void ExecuteOp(u32 op, u32 diff); - virtual bool InterpretList(); + virtual bool InterpretList(DisplayList &list); virtual void DrawSync(int mode); virtual void Continue(); virtual void Break(); @@ -88,18 +86,6 @@ private: u32 stallAddr; }; - CmdProcessorState dcontext; - - int dlIdGenerator; - - struct DisplayList { - int id; - u32 listpc; - u32 stall; - }; - - std::vector dlQueue; - u32 prev; u32 stack[2]; u32 stackptr; diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index a88d235a12..4a6262b411 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -128,6 +128,7 @@ + @@ -147,6 +148,7 @@ + @@ -162,4 +164,4 @@ - + \ No newline at end of file diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index e5a783590f..5f4cbc3c56 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -60,6 +60,10 @@ GLES + + + Common + @@ -101,6 +105,10 @@ GLES + + + Common + diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp new file mode 100644 index 0000000000..4b4f2d4826 --- /dev/null +++ b/GPU/GPUCommon.cpp @@ -0,0 +1,49 @@ +#include "GPUCommon.h" + +static int dlIdGenerator = 1; + +void init() { + dlIdGenerator = 1; +} + +int GPUCommon::listStatus(int listid) +{ + for(DisplayListQueue::iterator it(dlQueue.begin()); it != dlQueue.end(); ++it) + { + if(it->id == listid) + { + return it->status; + } + } + return 0x80000100; // INVALID_ID +} + +u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, bool head) +{ + DisplayList dl; + dl.id = dlIdGenerator++; + dl.pc = listpc & 0xFFFFFFF; + dl.stall = stall & 0xFFFFFFF; + dl.status = PSP_GE_LIST_QUEUED; + if(head) + dlQueue.push_front(dl); + else + dlQueue.push_back(dl); + ProcessDLQueue(); + return dl.id; +} + +void GPUCommon::UpdateStall(int listid, u32 newstall) +{ + // this needs improvement.... + for (DisplayListQueue::iterator iter = dlQueue.begin(); iter != dlQueue.end(); iter++) + { + DisplayList &l = *iter; + if (l.id == listid) + { + l.stall = newstall & 0xFFFFFFF; + } + } + + ProcessDLQueue(); +} \ No newline at end of file diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h new file mode 100644 index 0000000000..8b943dd1cf --- /dev/null +++ b/GPU/GPUCommon.h @@ -0,0 +1,24 @@ +#pragma once + +#include "GPUInterface.h" + +class GPUCommon : public GPUInterface +{ +public: + GPUCommon() : + dlIdGenerator(1), + currentList(NULL) + {} + + virtual bool ProcessDLQueue() = 0; + virtual void UpdateStall(int listid, u32 newstall); + virtual u32 EnqueueList(u32 listpc, u32 stall, bool head); + virtual int listStatus(int listid); + +protected: + typedef std::deque DisplayListQueue; + + int dlIdGenerator; + DisplayList *currentList; + DisplayListQueue dlQueue; +}; \ No newline at end of file diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 81d71d9a52..1208e542c0 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -18,6 +18,25 @@ #pragma once #include "../Globals.h" +#include + +enum DisplayListStatus +{ + PSP_GE_LIST_DONE = 0, // reached finish+end + PSP_GE_LIST_QUEUED = 1, // in queue, not stalled + PSP_GE_LIST_DRAWING = 2, // drawing + PSP_GE_LIST_STALL_REACHED = 3, // stalled + PSP_GE_LIST_END_REACHED = 4, // reached signal+end, in jpcsp but not in pspsdk? + PSP_GE_LIST_CANCEL_DONE = 5, // canceled? +}; + +struct DisplayList +{ + int id; + u32 pc; + u32 stall; + DisplayListStatus status; +}; class GPUInterface { @@ -29,13 +48,14 @@ public: // Draw queue management // TODO: Much of this should probably be shared between the different GPU implementations. - virtual u32 EnqueueList(u32 listpc, u32 stall) = 0; + virtual u32 EnqueueList(u32 listpc, u32 stall, bool head) = 0; virtual void UpdateStall(int listid, u32 newstall) = 0; virtual void DrawSync(int mode) = 0; virtual void Continue() = 0; virtual void ExecuteOp(u32 op, u32 diff) = 0; - virtual bool InterpretList() = 0; + virtual bool InterpretList(DisplayList& list) = 0; + virtual int listStatus(int listid) = 0; // Framebuffer management virtual void SetDisplayFramebuffer(u32 framebuf, u32 stride, int format) = 0; diff --git a/GPU/GPUState.cpp b/GPU/GPUState.cpp index c45d65ae88..d984cf0b33 100644 --- a/GPU/GPUState.cpp +++ b/GPU/GPUState.cpp @@ -95,7 +95,8 @@ void ReapplyGfxState() for (int i = GE_CMD_VERTEXTYPE; i < GE_CMD_BONEMATRIXNUMBER; i++) { - gpu->ExecuteOp(gstate.cmdmem[i], 0xFFFFFFFF); + if(i != GE_CMD_ORIGIN) + gpu->ExecuteOp(gstate.cmdmem[i], 0xFFFFFFFF); } // Can't write to bonematrixnumber here diff --git a/GPU/Null/NullGpu.cpp b/GPU/Null/NullGpu.cpp index 80d7fc9652..cf96262e30 100644 --- a/GPU/Null/NullGpu.cpp +++ b/GPU/Null/NullGpu.cpp @@ -22,29 +22,11 @@ #include "../../Core/MemMap.h" #include "../../Core/HLE/sceKernelInterrupt.h" -struct DisplayState -{ - u32 pc; - u32 stallAddr; -}; - -static DisplayState dcontext; - -struct DisplayList -{ - int id; - u32 listpc; - u32 stall; -}; - -static std::vector dlQueue; - static u32 prev; static u32 stack[2]; static u32 stackptr = 0; static bool finished; -static int dlIdGenerator = 1; NullGPU::NullGPU() { @@ -59,17 +41,13 @@ NullGPU::~NullGPU() bool NullGPU::ProcessDLQueue() { - std::vector::iterator iter = dlQueue.begin(); + DisplayListQueue::iterator iter = dlQueue.begin(); while (!(iter == dlQueue.end())) { DisplayList &l = *iter; - dcontext.pc = l.listpc; - dcontext.stallAddr = l.stall; // DEBUG_LOG(G3D,"Okay, starting DL execution at %08 - stall = %08x", context.pc, stallAddr); - if (!InterpretList()) + if (!InterpretList(l)) { - l.listpc = dcontext.pc; - l.stall = dcontext.stallAddr; return false; } else @@ -83,34 +61,6 @@ bool NullGPU::ProcessDLQueue() return true; //no more lists! } -u32 NullGPU::EnqueueList(u32 listpc, u32 stall) -{ - DisplayList dl; - dl.id = dlIdGenerator++; - dl.listpc = listpc&0xFFFFFFF; - dl.stall = stall&0xFFFFFFF; - dlQueue.push_back(dl); - if (!ProcessDLQueue()) - return dl.id; - else - return 0; -} - -void NullGPU::UpdateStall(int listid, u32 newstall) -{ - // this needs improvement.... - for (std::vector::iterator iter = dlQueue.begin(); iter != dlQueue.end(); iter++) - { - DisplayList &l = *iter; - if (l.id == listid) - { - l.stall = newstall & 0xFFFFFFF; - } - } - - ProcessDLQueue(); -} - void NullGPU::DrawSync(int mode) { if (mode == 0) // Wait for completion @@ -187,18 +137,18 @@ void NullGPU::ExecuteOp(u32 op, u32 diff) case GE_CMD_JUMP: { u32 target = (((gstate.base & 0x00FF0000) << 8) | (op & 0xFFFFFC)) & 0x0FFFFFFF; - DEBUG_LOG(G3D,"DL CMD JUMP - %08x to %08x", dcontext.pc, target); - dcontext.pc = target - 4; // pc will be increased after we return, counteract that + DEBUG_LOG(G3D,"DL CMD JUMP - %08x to %08x", currentList->pc, target); + currentList->pc = target - 4; // pc will be increased after we return, counteract that } break; case GE_CMD_CALL: { - u32 retval = dcontext.pc + 4; + u32 retval = currentList->pc + 4; stack[stackptr++] = retval; u32 target = (((gstate.base & 0x00FF0000) << 8) | (op & 0xFFFFFC)) & 0xFFFFFFF; - DEBUG_LOG(G3D,"DL CMD CALL - %08x to %08x, ret=%08x", dcontext.pc, target, retval); - dcontext.pc = target - 4; // pc will be increased after we return, counteract that + DEBUG_LOG(G3D,"DL CMD CALL - %08x to %08x, ret=%08x", currentList->pc, target, retval); + currentList->pc = target - 4; // pc will be increased after we return, counteract that } break; @@ -206,8 +156,8 @@ void NullGPU::ExecuteOp(u32 op, u32 diff) //TODO : debug! { u32 target = stack[--stackptr] & 0xFFFFFFF; - DEBUG_LOG(G3D,"DL CMD RET - from %08x to %08x", dcontext.pc, target); - dcontext.pc = target - 4; + DEBUG_LOG(G3D,"DL CMD RET - from %08x to %08x", currentList->pc, target); + currentList->pc = target - 4; } break; @@ -234,7 +184,7 @@ void NullGPU::ExecuteOp(u32 op, u32 diff) break; case GE_CMD_ORIGIN: - gstate.offsetAddr = dcontext.pc & 0xFFFFFF; + gstate.offsetAddr = currentList->pc & 0xFFFFFF; break; case GE_CMD_VERTEXTYPE: @@ -807,15 +757,16 @@ void NullGPU::ExecuteOp(u32 op, u32 diff) break; default: - DEBUG_LOG(G3D,"DL Unknown: %08x @ %08x", op, dcontext.pc); + DEBUG_LOG(G3D,"DL Unknown: %08x @ %08x", op, currentList->pc); break; //ETC... } } -bool NullGPU::InterpretList() +bool NullGPU::InterpretList(DisplayList &list) { + currentList = &list; // Reset stackptr for safety stackptr = 0; u32 op = 0; @@ -823,17 +774,19 @@ bool NullGPU::InterpretList() finished = false; while (!finished) { - if (dcontext.pc == dcontext.stallAddr) + if (currentList->pc == currentList->stall) + { + currentList->status = PSP_GE_LIST_STALL_REACHED; return false; - - op = Memory::ReadUnchecked_U32(dcontext.pc); //read from memory + } + op = Memory::ReadUnchecked_U32(currentList->pc); //read from memory u32 cmd = op >> 24; u32 diff = op ^ gstate.cmdmem[cmd]; gstate.cmdmem[cmd] = op; // crashes if I try to put the whole op there?? ExecuteOp(op, diff); - dcontext.pc += 4; + currentList->pc += 4; prev = op; } return true; diff --git a/GPU/Null/NullGpu.h b/GPU/Null/NullGpu.h index 5e9f163713..8d3c0191f7 100644 --- a/GPU/Null/NullGpu.h +++ b/GPU/Null/NullGpu.h @@ -17,20 +17,18 @@ #pragma once -#include "../GPUInterface.h" +#include "../GPUCommon.h" class ShaderManager; -class NullGPU : public GPUInterface +class NullGPU : public GPUCommon { public: NullGPU(); ~NullGPU(); virtual void InitClear() {} - virtual u32 EnqueueList(u32 listpc, u32 stall); - virtual void UpdateStall(int listid, u32 newstall); virtual void ExecuteOp(u32 op, u32 diff); - virtual bool InterpretList(); + virtual bool InterpretList(DisplayList &list); virtual void Continue(); virtual void DrawSync(int mode); virtual void EnableInterrupts(bool enable) { From 36a71eafd06deb4eb44b83ff62e575e6a565d121 Mon Sep 17 00:00:00 2001 From: Florent Castelli Date: Sat, 29 Dec 2012 02:10:29 +0100 Subject: [PATCH 06/89] Move InterpretList and ProcessDLQueue to GPUCommon --- GPU/GLES/DisplayListInterpreter.cpp | 73 ++++------------------------- GPU/GLES/DisplayListInterpreter.h | 11 +---- GPU/GPUCommon.cpp | 71 ++++++++++++++++++++++++++++ GPU/GPUCommon.h | 21 +++++++-- GPU/GPUInterface.h | 1 + GPU/Null/NullGpu.cpp | 59 ----------------------- GPU/Null/NullGpu.h | 2 - 7 files changed, 98 insertions(+), 140 deletions(-) diff --git a/GPU/GLES/DisplayListInterpreter.cpp b/GPU/GLES/DisplayListInterpreter.cpp index b6a0e3ec85..1ca7c42e4d 100644 --- a/GPU/GLES/DisplayListInterpreter.cpp +++ b/GPU/GLES/DisplayListInterpreter.cpp @@ -161,9 +161,7 @@ GLES_GPU::GLES_GPU(int renderWidth, int renderHeight) : interruptsEnabled_(true), displayFramebufPtr_(0), renderWidth_(renderWidth), - renderHeight_(renderHeight), - dumpThisFrame_(false), - dumpNextFrame_(false) + renderHeight_(renderHeight) { renderWidthFactor_ = (float)renderWidth / 480.0f; renderHeightFactor_ = (float)renderHeight / 272.0f; @@ -386,26 +384,6 @@ void GLES_GPU::EndDebugDraw() { // Render queue -bool GLES_GPU::ProcessDLQueue() -{ - DisplayListQueue::iterator iter = dlQueue.begin(); - while (!(iter == dlQueue.end())) - { - DisplayList &l = *iter; -// DEBUG_LOG(G3D,"Okay, starting DL execution at %08 - stall = %08x", context.pc, stallAddr); - if (!InterpretList(l)) - { - return false; - } else { - //At the end, we can remove it from the queue and continue - dlQueue.erase(iter); - //this invalidated the iterator, let's fix it - iter = dlQueue.begin(); - } - } - return true; //no more lists! -} - void GLES_GPU::DrawSync(int mode) { transformDraw_.Flush(); @@ -439,6 +417,13 @@ static void LeaveClearMode() { // dirtyshader? } +void GLES_GPU::PreExecuteOp(u32 op, u32 diff) { + u32 cmd = op >> 24; + + if (flushBeforeCommand_[cmd] == 1 || (diff && flushBeforeCommand_[cmd] == 2)) + transformDraw_.Flush(); +} + void GLES_GPU::ExecuteOp(u32 op, u32 diff) { u32 cmd = op >> 24; u32 data = op & 0xFFFFFF; @@ -1077,48 +1062,6 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { } } -bool GLES_GPU::InterpretList(DisplayList &list) -{ - currentList = &list; - // Reset stackptr for safety - stackptr = 0; - u32 op = 0; - prev = 0; - finished = false; - while (!finished) - { - list.status = PSP_GE_LIST_DRAWING; - if (!Memory::IsValidAddress(list.pc)) { - ERROR_LOG(G3D, "DL PC = %08x WTF!!!!", list.pc); - return true; - } - if (list.pc == list.stall) - { - list.status = PSP_GE_LIST_STALL_REACHED; - return false; - } - op = Memory::ReadUnchecked_U32(list.pc); //read from memory - u32 cmd = op >> 24; - u32 diff = op ^ gstate.cmdmem[cmd]; - if (flushBeforeCommand_[cmd] == 1 || (diff && flushBeforeCommand_[cmd] == 2)) - transformDraw_.Flush(); - // TODO: Add a compiler flag to remove stuff like this at very-final build time. - if (dumpThisFrame_) { - char temp[256]; - GeDisassembleOp(list.pc, op, prev, temp); - NOTICE_LOG(G3D, "%08x: %s", list.pc, temp); - } - - gstate.cmdmem[cmd] = op; - - ExecuteOp(op, diff); - - list.pc += 4; - prev = op; - } - return true; -} - void GLES_GPU::UpdateStats() { gpuStats.numVertexShaders = shaderManager_->NumVertexShaders(); gpuStats.numFragmentShaders = shaderManager_->NumFragmentShaders(); diff --git a/GPU/GLES/DisplayListInterpreter.h b/GPU/GLES/DisplayListInterpreter.h index 49e20eac88..70590c3c84 100644 --- a/GPU/GLES/DisplayListInterpreter.h +++ b/GPU/GLES/DisplayListInterpreter.h @@ -35,8 +35,8 @@ public: GLES_GPU(int renderWidth, int renderHeight); ~GLES_GPU(); virtual void InitClear(); + virtual void PreExecuteOp(u32 op, u32 diff); virtual void ExecuteOp(u32 op, u32 diff); - virtual bool InterpretList(DisplayList &list); virtual void DrawSync(int mode); virtual void Continue(); virtual void Break(); @@ -56,7 +56,6 @@ public: private: void DoBlockTransfer(); - bool ProcessDLQueue(); // Applies states for debugging if enabled. void BeginDebugDraw(); @@ -78,19 +77,11 @@ private: float renderWidthFactor_; float renderHeightFactor_; - bool dumpNextFrame_; - bool dumpThisFrame_; - struct CmdProcessorState { u32 pc; u32 stallAddr; }; - u32 prev; - u32 stack[2]; - u32 stackptr; - bool finished; - struct VirtualFramebuffer { u32 fb_address; u32 z_address; diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 4b4f2d4826..32ebb12465 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1,4 +1,9 @@ +#include "../Core/MemMap.h" +#include "GeDisasm.h" #include "GPUCommon.h" +#include "GPUState.h" + + static int dlIdGenerator = 1; @@ -46,4 +51,70 @@ void GPUCommon::UpdateStall(int listid, u32 newstall) } ProcessDLQueue(); +} + +bool GPUCommon::InterpretList(DisplayList &list) +{ + currentList = &list; + // Reset stackptr for safety + stackptr = 0; + u32 op = 0; + prev = 0; + finished = false; + while (!finished) + { + list.status = PSP_GE_LIST_DRAWING; + if (!Memory::IsValidAddress(list.pc)) { + ERROR_LOG(G3D, "DL PC = %08x WTF!!!!", list.pc); + return true; + } + if (list.pc == list.stall) + { + list.status = PSP_GE_LIST_STALL_REACHED; + return false; + } + op = Memory::ReadUnchecked_U32(list.pc); //read from memory + u32 cmd = op >> 24; + u32 diff = op ^ gstate.cmdmem[cmd]; + PreExecuteOp(op, diff); + // TODO: Add a compiler flag to remove stuff like this at very-final build time. + if (dumpThisFrame_) { + char temp[256]; + GeDisassembleOp(list.pc, op, prev, temp); + NOTICE_LOG(G3D, "%s", temp); + } + gstate.cmdmem[cmd] = op; // crashes if I try to put the whole op there?? + + ExecuteOp(op, diff); + + list.pc += 4; + prev = op; + } + return true; +} + +bool GPUCommon::ProcessDLQueue() +{ + DisplayListQueue::iterator iter = dlQueue.begin(); + while (!(iter == dlQueue.end())) + { + DisplayList &l = *iter; + DEBUG_LOG(G3D,"Okay, starting DL execution at %08x - stall = %08x", l.pc, l.stall); + if (!InterpretList(l)) + { + return false; + } + else + { + //At the end, we can remove it from the queue and continue + dlQueue.erase(iter); + //this invalidated the iterator, let's fix it + iter = dlQueue.begin(); + } + } + return true; //no more lists! +} + +void GPUCommon::PreExecuteOp(u32 op, u32 diff) { + // Nothing to do } \ No newline at end of file diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 8b943dd1cf..03a31b1344 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -7,18 +7,31 @@ class GPUCommon : public GPUInterface public: GPUCommon() : dlIdGenerator(1), - currentList(NULL) + currentList(NULL), + stackptr(0), + dumpThisFrame_(false), + dumpNextFrame_(false) {} - - virtual bool ProcessDLQueue() = 0; + + virtual void PreExecuteOp(u32 op, u32 diff); + virtual bool InterpretList(DisplayList &list); + virtual bool ProcessDLQueue(); virtual void UpdateStall(int listid, u32 newstall); virtual u32 EnqueueList(u32 listpc, u32 stall, bool head); virtual int listStatus(int listid); protected: typedef std::deque DisplayListQueue; - + int dlIdGenerator; DisplayList *currentList; DisplayListQueue dlQueue; + + u32 prev; + u32 stack[2]; + u32 stackptr; + bool finished; + + bool dumpNextFrame_; + bool dumpThisFrame_; }; \ No newline at end of file diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 1208e542c0..ac45316451 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -53,6 +53,7 @@ public: virtual void DrawSync(int mode) = 0; virtual void Continue() = 0; + virtual void PreExecuteOp(u32 op, u32 diff) = 0; virtual void ExecuteOp(u32 op, u32 diff) = 0; virtual bool InterpretList(DisplayList& list) = 0; virtual int listStatus(int listid) = 0; diff --git a/GPU/Null/NullGpu.cpp b/GPU/Null/NullGpu.cpp index cf96262e30..8518704b7e 100644 --- a/GPU/Null/NullGpu.cpp +++ b/GPU/Null/NullGpu.cpp @@ -22,43 +22,13 @@ #include "../../Core/MemMap.h" #include "../../Core/HLE/sceKernelInterrupt.h" -static u32 prev; -static u32 stack[2]; -static u32 stackptr = 0; -static bool finished; - - NullGPU::NullGPU() { interruptsEnabled_ = true; - dlIdGenerator = 1; } NullGPU::~NullGPU() { - dlQueue.clear(); -} - -bool NullGPU::ProcessDLQueue() -{ - DisplayListQueue::iterator iter = dlQueue.begin(); - while (!(iter == dlQueue.end())) - { - DisplayList &l = *iter; -// DEBUG_LOG(G3D,"Okay, starting DL execution at %08 - stall = %08x", context.pc, stallAddr); - if (!InterpretList(l)) - { - return false; - } - else - { - //At the end, we can remove it from the queue and continue - dlQueue.erase(iter); - //this invalidated the iterator, let's fix it - iter = dlQueue.begin(); - } - } - return true; //no more lists! } void NullGPU::DrawSync(int mode) @@ -74,7 +44,6 @@ void NullGPU::Continue() } - void NullGPU::ExecuteOp(u32 op, u32 diff) { u32 cmd = op >> 24; @@ -764,34 +733,6 @@ void NullGPU::ExecuteOp(u32 op, u32 diff) } } -bool NullGPU::InterpretList(DisplayList &list) -{ - currentList = &list; - // Reset stackptr for safety - stackptr = 0; - u32 op = 0; - prev = 0; - finished = false; - while (!finished) - { - if (currentList->pc == currentList->stall) - { - currentList->status = PSP_GE_LIST_STALL_REACHED; - return false; - } - op = Memory::ReadUnchecked_U32(currentList->pc); //read from memory - u32 cmd = op >> 24; - u32 diff = op ^ gstate.cmdmem[cmd]; - gstate.cmdmem[cmd] = op; // crashes if I try to put the whole op there?? - - ExecuteOp(op, diff); - - currentList->pc += 4; - prev = op; - } - return true; -} - void NullGPU::UpdateStats() { gpuStats.numVertexShaders = 0; diff --git a/GPU/Null/NullGpu.h b/GPU/Null/NullGpu.h index 8d3c0191f7..1dabc32e42 100644 --- a/GPU/Null/NullGpu.h +++ b/GPU/Null/NullGpu.h @@ -28,7 +28,6 @@ public: ~NullGPU(); virtual void InitClear() {} virtual void ExecuteOp(u32 op, u32 diff); - virtual bool InterpretList(DisplayList &list); virtual void Continue(); virtual void DrawSync(int mode); virtual void EnableInterrupts(bool enable) { @@ -46,6 +45,5 @@ public: virtual void DumpNextFrame() {} private: - bool ProcessDLQueue(); bool interruptsEnabled_; }; From df627f77388f5d18cc299ce465fe5164e15aecbb Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 28 Dec 2012 18:13:32 -0800 Subject: [PATCH 07/89] Save states using gzip, load either way. Could implement an option to save states uncompressed. There's a small performance hit. Test files were 8% - 14% the size, but these are just from menus/etc. --- Common/ChunkFile.h | 14 ++++----- Common/FileUtil.cpp | 77 ++++++++++++++++++++++++++++++++++++--------- Common/FileUtil.h | 41 +++++++++++++++++++----- 3 files changed, 104 insertions(+), 28 deletions(-) diff --git a/Common/ChunkFile.h b/Common/ChunkFile.h index 1671cecc8a..b97a33b90e 100644 --- a/Common/ChunkFile.h +++ b/Common/ChunkFile.h @@ -369,7 +369,7 @@ public: if (!File::Exists(_rFilename)) return false; - // Check file size + // Check file size - most probably it can't compress THAT well. const u64 fileSize = File::GetSize(_rFilename); static const u64 headerSize = sizeof(SChunkHeader); if (fileSize < headerSize) @@ -378,7 +378,7 @@ public: return false; } - File::IOFile pFile(_rFilename, "rb"); + File::IOFile pFile(_rFilename, "rb", File::METHOD_GZIP); if (!pFile) { ERROR_LOG(COMMON,"ChunkReader: Can't open file for reading"); @@ -402,11 +402,11 @@ public: } // get size - const int sz = (int)(fileSize - headerSize); - if (header.ExpectedSize != sz) + const int sz = header.ExpectedSize; + if (sz > 128 * 1024 * 1024) { - ERROR_LOG(COMMON,"ChunkReader: Bad file size, got %d expected %d", - sz, header.ExpectedSize); + ERROR_LOG(COMMON,"ChunkReader: File too large, got %d bytes", + header.ExpectedSize); return false; } @@ -432,7 +432,7 @@ public: static bool Save(const std::string& _rFilename, int _Revision, T& _class) { INFO_LOG(COMMON, "ChunkReader: Writing %s" , _rFilename.c_str()); - File::IOFile pFile(_rFilename, "wb"); + File::IOFile pFile(_rFilename, "wb9", File::METHOD_GZIP); if (!pFile) { ERROR_LOG(COMMON,"ChunkReader: Error opening file for write"); diff --git a/Common/FileUtil.cpp b/Common/FileUtil.cpp index 8ba82fa901..47207e00a7 100644 --- a/Common/FileUtil.cpp +++ b/Common/FileUtil.cpp @@ -767,17 +767,17 @@ bool ReadFileToString(bool text_file, const char *filename, std::string &str) } IOFile::IOFile() - : m_file(NULL), m_good(true) + : m_file(NULL), m_zFile(NULL), m_good(true) {} IOFile::IOFile(std::FILE* file) - : m_file(file), m_good(true) + : m_file(file), m_zFile(NULL), m_good(true) {} -IOFile::IOFile(const std::string& filename, const char openmode[]) - : m_file(NULL), m_good(true) +IOFile::IOFile(const std::string& filename, const char openmode[], IOFileMethod method) + : m_file(NULL), m_zFile(NULL), m_good(true), m_method(method) { - Open(filename, openmode); + Open(filename, openmode, method); } IOFile::~IOFile() @@ -785,14 +785,21 @@ IOFile::~IOFile() Close(); } -bool IOFile::Open(const std::string& filename, const char openmode[]) +bool IOFile::Open(const std::string& filename, const char openmode[], IOFileMethod method) { Close(); + + m_method = method; + if (0 != (m_method & METHOD_GZIP)) + m_zFile = gzopen(filename.c_str(), openmode); + else + { #ifdef _WIN32 - fopen_s(&m_file, filename.c_str(), openmode); + fopen_s(&m_file, filename.c_str(), openmode); #else - m_file = fopen(filename.c_str(), openmode); + m_file = fopen(filename.c_str(), openmode); #endif + } m_good = IsOpen(); return m_good; @@ -800,10 +807,19 @@ bool IOFile::Open(const std::string& filename, const char openmode[]) bool IOFile::Close() { - if (!IsOpen() || 0 != std::fclose(m_file)) - m_good = false; + if (0 != (m_method & METHOD_GZIP)) + { + if (Z_OK != gzclose(m_zFile)) + m_good = false; + m_zFile = NULL; + } + else + { + if (!IsOpen() || 0 != std::fclose(m_file)) + m_good = false; + m_file = NULL; + } - m_file = NULL; return m_good; } @@ -819,19 +835,32 @@ void IOFile::SetHandle(std::FILE* file) Close(); Clear(); m_file = file; + m_method = METHOD_STANDARD; } u64 IOFile::GetSize() { if (IsOpen()) + { + // Not supported. + if (0 != (m_method & METHOD_GZIP)) + return 0; return File::GetSize(m_file); + } else return 0; } bool IOFile::Seek(s64 off, int origin) { - if (!IsOpen() || 0 != fseeko(m_file, off, origin)) + if (!IsOpen()) + m_good = false; + else if (0 != (m_method & METHOD_GZIP)) + { + if (-1 == gzseek(m_zFile, (z_off_t) off, origin)) + m_good = false; + } + else if (0 != fseeko(m_file, off, origin)) m_good = false; return m_good; @@ -840,14 +869,26 @@ bool IOFile::Seek(s64 off, int origin) u64 IOFile::Tell() { if (IsOpen()) + { + if (0 != (m_method & METHOD_GZIP)) + return gztell(m_zFile); + return ftello(m_file); + } else return -1; } bool IOFile::Flush() { - if (!IsOpen() || 0 != std::fflush(m_file)) + if (!IsOpen()) + m_good = false; + else if (0 != (m_method & METHOD_GZIP)) + { + if (-1 == gzflush(m_zFile, Z_PARTIAL_FLUSH)) + m_good = false; + } + else if (0 != std::fflush(m_file)) m_good = false; return m_good; @@ -855,7 +896,15 @@ bool IOFile::Flush() bool IOFile::Resize(u64 size) { - if (!IsOpen() || 0 != + if (!IsOpen()) + m_good = false; + else if (0 != (m_method & METHOD_GZIP)) + { + // gzseek() adds nulls to the seeked location. + if (-1 == gzseek(m_zFile, (z_off_t) size, SEEK_SET)) + m_good = false; + } + else if (0 != #ifdef _WIN32 // ector: _chsize sucks, not 64-bit safe // F|RES: changed to _chsize_s. i think it is 64-bit safe diff --git a/Common/FileUtil.h b/Common/FileUtil.h index 4c9a86f5cf..12a79ea730 100644 --- a/Common/FileUtil.h +++ b/Common/FileUtil.h @@ -25,6 +25,7 @@ #include #include "Common.h" +#include "../ext/zlib/zlib.h" // User directory indices for GetUserPath enum { @@ -124,6 +125,13 @@ std::string &GetExeDirectory(); bool WriteStringToFile(bool text_file, const std::string &str, const char *filename); bool ReadFileToString(bool text_file, const char *filename, std::string &str); +enum IOFileMethod +{ + METHOD_STANDARD = 0x00, + // Warning: may not be 64-bit safe. + METHOD_GZIP = 0x01, +}; + // simple wrapper for cstdlib file functions to // hopefully will make error checking easier // and make forgetting an fclose() harder @@ -132,17 +140,24 @@ class IOFile : NonCopyable public: IOFile(); IOFile(std::FILE* file); - IOFile(const std::string& filename, const char openmode[]); + IOFile(const std::string& filename, const char openmode[], IOFileMethod method = METHOD_STANDARD); ~IOFile(); - bool Open(const std::string& filename, const char openmode[]); + bool Open(const std::string& filename, const char openmode[], IOFileMethod method = METHOD_STANDARD); bool Close(); template bool ReadArray(T* data, size_t length) { - if (!IsOpen() || length != std::fread(data, sizeof(T), length, m_file)) + if (!IsOpen()) + m_good = false; + else if (0 != (m_method & METHOD_GZIP)) + { + if (sizeof(T) * length != gzread(m_zFile, data, sizeof(T) * length)) + m_good = false; + } + else if (length != std::fread(data, sizeof(T), length, m_file)) m_good = false; return m_good; @@ -151,7 +166,14 @@ public: template bool WriteArray(const T* data, size_t length) { - if (!IsOpen() || length != std::fwrite(data, sizeof(T), length, m_file)) + if (!IsOpen()) + m_good = false; + else if (0 != (m_method & METHOD_GZIP)) + { + if (sizeof(T) * length != gzwrite(m_zFile, data, sizeof(T) * length)) + m_good = false; + } + else if (length != std::fwrite(data, sizeof(T), length, m_file)) m_good = false; return m_good; @@ -167,11 +189,11 @@ public: return WriteArray(reinterpret_cast(data), length); } - bool IsOpen() { return NULL != m_file; } + bool IsOpen() { return NULL != m_file || NULL != m_zFile; } // m_good is set to false when a read, write or other function fails bool IsGood() { return m_good; } - operator void*() { return m_good ? m_file : NULL; } + operator void*() { return m_good ? (NULL != m_file ? m_file : m_zFile) : NULL; } std::FILE* ReleaseHandle(); @@ -189,13 +211,18 @@ public: void Clear() { m_good = true; #undef clearerr - std::clearerr(m_file); + if (NULL != m_file) + std::clearerr(m_file); + if (NULL != m_zFile) + gzclearerr(m_zFile); } private: IOFile& operator=(const IOFile&) /*= delete*/; std::FILE* m_file; + gzFile m_zFile; + IOFileMethod m_method; bool m_good; }; From e03044b2416983889b9bedb7d069c694d830bc66 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 28 Dec 2012 23:30:43 -0800 Subject: [PATCH 08/89] Fix a crash with FPL objects in save states. --- Core/HLE/sceKernelMemory.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index 97ce91136b..9ac86fc5ae 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -86,6 +86,8 @@ struct FPL : public KernelObject virtual void DoState(PointerWrap &p) { p.Do(nf); + if (p.mode == p.MODE_READ) + blocks = new bool[nf.numBlocks]; p.DoArray(blocks, nf.numBlocks); p.Do(address); p.DoMarker("FPL"); From 1d8b90259147e0c21ab0f97ff90e151a6e855251 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 28 Dec 2012 23:57:11 -0800 Subject: [PATCH 09/89] Revert "Save states using gzip, load either way." This reverts commit df627f77388f5d18cc299ce465fe5164e15aecbb. --- Common/ChunkFile.h | 14 ++++----- Common/FileUtil.cpp | 77 +++++++++------------------------------------ Common/FileUtil.h | 41 +++++------------------- 3 files changed, 28 insertions(+), 104 deletions(-) diff --git a/Common/ChunkFile.h b/Common/ChunkFile.h index b97a33b90e..1671cecc8a 100644 --- a/Common/ChunkFile.h +++ b/Common/ChunkFile.h @@ -369,7 +369,7 @@ public: if (!File::Exists(_rFilename)) return false; - // Check file size - most probably it can't compress THAT well. + // Check file size const u64 fileSize = File::GetSize(_rFilename); static const u64 headerSize = sizeof(SChunkHeader); if (fileSize < headerSize) @@ -378,7 +378,7 @@ public: return false; } - File::IOFile pFile(_rFilename, "rb", File::METHOD_GZIP); + File::IOFile pFile(_rFilename, "rb"); if (!pFile) { ERROR_LOG(COMMON,"ChunkReader: Can't open file for reading"); @@ -402,11 +402,11 @@ public: } // get size - const int sz = header.ExpectedSize; - if (sz > 128 * 1024 * 1024) + const int sz = (int)(fileSize - headerSize); + if (header.ExpectedSize != sz) { - ERROR_LOG(COMMON,"ChunkReader: File too large, got %d bytes", - header.ExpectedSize); + ERROR_LOG(COMMON,"ChunkReader: Bad file size, got %d expected %d", + sz, header.ExpectedSize); return false; } @@ -432,7 +432,7 @@ public: static bool Save(const std::string& _rFilename, int _Revision, T& _class) { INFO_LOG(COMMON, "ChunkReader: Writing %s" , _rFilename.c_str()); - File::IOFile pFile(_rFilename, "wb9", File::METHOD_GZIP); + File::IOFile pFile(_rFilename, "wb"); if (!pFile) { ERROR_LOG(COMMON,"ChunkReader: Error opening file for write"); diff --git a/Common/FileUtil.cpp b/Common/FileUtil.cpp index 47207e00a7..8ba82fa901 100644 --- a/Common/FileUtil.cpp +++ b/Common/FileUtil.cpp @@ -767,17 +767,17 @@ bool ReadFileToString(bool text_file, const char *filename, std::string &str) } IOFile::IOFile() - : m_file(NULL), m_zFile(NULL), m_good(true) + : m_file(NULL), m_good(true) {} IOFile::IOFile(std::FILE* file) - : m_file(file), m_zFile(NULL), m_good(true) + : m_file(file), m_good(true) {} -IOFile::IOFile(const std::string& filename, const char openmode[], IOFileMethod method) - : m_file(NULL), m_zFile(NULL), m_good(true), m_method(method) +IOFile::IOFile(const std::string& filename, const char openmode[]) + : m_file(NULL), m_good(true) { - Open(filename, openmode, method); + Open(filename, openmode); } IOFile::~IOFile() @@ -785,21 +785,14 @@ IOFile::~IOFile() Close(); } -bool IOFile::Open(const std::string& filename, const char openmode[], IOFileMethod method) +bool IOFile::Open(const std::string& filename, const char openmode[]) { Close(); - - m_method = method; - if (0 != (m_method & METHOD_GZIP)) - m_zFile = gzopen(filename.c_str(), openmode); - else - { #ifdef _WIN32 - fopen_s(&m_file, filename.c_str(), openmode); + fopen_s(&m_file, filename.c_str(), openmode); #else - m_file = fopen(filename.c_str(), openmode); + m_file = fopen(filename.c_str(), openmode); #endif - } m_good = IsOpen(); return m_good; @@ -807,19 +800,10 @@ bool IOFile::Open(const std::string& filename, const char openmode[], IOFileMeth bool IOFile::Close() { - if (0 != (m_method & METHOD_GZIP)) - { - if (Z_OK != gzclose(m_zFile)) - m_good = false; - m_zFile = NULL; - } - else - { - if (!IsOpen() || 0 != std::fclose(m_file)) - m_good = false; - m_file = NULL; - } + if (!IsOpen() || 0 != std::fclose(m_file)) + m_good = false; + m_file = NULL; return m_good; } @@ -835,32 +819,19 @@ void IOFile::SetHandle(std::FILE* file) Close(); Clear(); m_file = file; - m_method = METHOD_STANDARD; } u64 IOFile::GetSize() { if (IsOpen()) - { - // Not supported. - if (0 != (m_method & METHOD_GZIP)) - return 0; return File::GetSize(m_file); - } else return 0; } bool IOFile::Seek(s64 off, int origin) { - if (!IsOpen()) - m_good = false; - else if (0 != (m_method & METHOD_GZIP)) - { - if (-1 == gzseek(m_zFile, (z_off_t) off, origin)) - m_good = false; - } - else if (0 != fseeko(m_file, off, origin)) + if (!IsOpen() || 0 != fseeko(m_file, off, origin)) m_good = false; return m_good; @@ -869,26 +840,14 @@ bool IOFile::Seek(s64 off, int origin) u64 IOFile::Tell() { if (IsOpen()) - { - if (0 != (m_method & METHOD_GZIP)) - return gztell(m_zFile); - return ftello(m_file); - } else return -1; } bool IOFile::Flush() { - if (!IsOpen()) - m_good = false; - else if (0 != (m_method & METHOD_GZIP)) - { - if (-1 == gzflush(m_zFile, Z_PARTIAL_FLUSH)) - m_good = false; - } - else if (0 != std::fflush(m_file)) + if (!IsOpen() || 0 != std::fflush(m_file)) m_good = false; return m_good; @@ -896,15 +855,7 @@ bool IOFile::Flush() bool IOFile::Resize(u64 size) { - if (!IsOpen()) - m_good = false; - else if (0 != (m_method & METHOD_GZIP)) - { - // gzseek() adds nulls to the seeked location. - if (-1 == gzseek(m_zFile, (z_off_t) size, SEEK_SET)) - m_good = false; - } - else if (0 != + if (!IsOpen() || 0 != #ifdef _WIN32 // ector: _chsize sucks, not 64-bit safe // F|RES: changed to _chsize_s. i think it is 64-bit safe diff --git a/Common/FileUtil.h b/Common/FileUtil.h index 12a79ea730..4c9a86f5cf 100644 --- a/Common/FileUtil.h +++ b/Common/FileUtil.h @@ -25,7 +25,6 @@ #include #include "Common.h" -#include "../ext/zlib/zlib.h" // User directory indices for GetUserPath enum { @@ -125,13 +124,6 @@ std::string &GetExeDirectory(); bool WriteStringToFile(bool text_file, const std::string &str, const char *filename); bool ReadFileToString(bool text_file, const char *filename, std::string &str); -enum IOFileMethod -{ - METHOD_STANDARD = 0x00, - // Warning: may not be 64-bit safe. - METHOD_GZIP = 0x01, -}; - // simple wrapper for cstdlib file functions to // hopefully will make error checking easier // and make forgetting an fclose() harder @@ -140,24 +132,17 @@ class IOFile : NonCopyable public: IOFile(); IOFile(std::FILE* file); - IOFile(const std::string& filename, const char openmode[], IOFileMethod method = METHOD_STANDARD); + IOFile(const std::string& filename, const char openmode[]); ~IOFile(); - bool Open(const std::string& filename, const char openmode[], IOFileMethod method = METHOD_STANDARD); + bool Open(const std::string& filename, const char openmode[]); bool Close(); template bool ReadArray(T* data, size_t length) { - if (!IsOpen()) - m_good = false; - else if (0 != (m_method & METHOD_GZIP)) - { - if (sizeof(T) * length != gzread(m_zFile, data, sizeof(T) * length)) - m_good = false; - } - else if (length != std::fread(data, sizeof(T), length, m_file)) + if (!IsOpen() || length != std::fread(data, sizeof(T), length, m_file)) m_good = false; return m_good; @@ -166,14 +151,7 @@ public: template bool WriteArray(const T* data, size_t length) { - if (!IsOpen()) - m_good = false; - else if (0 != (m_method & METHOD_GZIP)) - { - if (sizeof(T) * length != gzwrite(m_zFile, data, sizeof(T) * length)) - m_good = false; - } - else if (length != std::fwrite(data, sizeof(T), length, m_file)) + if (!IsOpen() || length != std::fwrite(data, sizeof(T), length, m_file)) m_good = false; return m_good; @@ -189,11 +167,11 @@ public: return WriteArray(reinterpret_cast(data), length); } - bool IsOpen() { return NULL != m_file || NULL != m_zFile; } + bool IsOpen() { return NULL != m_file; } // m_good is set to false when a read, write or other function fails bool IsGood() { return m_good; } - operator void*() { return m_good ? (NULL != m_file ? m_file : m_zFile) : NULL; } + operator void*() { return m_good ? m_file : NULL; } std::FILE* ReleaseHandle(); @@ -211,18 +189,13 @@ public: void Clear() { m_good = true; #undef clearerr - if (NULL != m_file) - std::clearerr(m_file); - if (NULL != m_zFile) - gzclearerr(m_zFile); + std::clearerr(m_file); } private: IOFile& operator=(const IOFile&) /*= delete*/; std::FILE* m_file; - gzFile m_zFile; - IOFileMethod m_method; bool m_good; }; From 17eec66a0442398a93708d27c7f5ce5403bb006d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 29 Dec 2012 09:07:04 +0100 Subject: [PATCH 10/89] Restore run/pause shortcut. Reset doesn't need a shortcut. --- Windows/ppsspp.rc | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index aeb975be72..0eafb5b937 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -35,7 +35,7 @@ BEGIN DEFPUSHBUTTON "Step &Into",IDC_STEP,179,0,39,14 PUSHBUTTON "Step &Over",IDC_STEPOVER,219,0,40,14 PUSHBUTTON "S&kip",IDC_SKIP,265,0,23,14 -PUSHBUTTON "Next &HLE",IDC_STEPHLE,294,0,40,14 + PUSHBUTTON "Next &HLE",IDC_STEPHLE,294,0,40,14 EDITTEXT IDC_ADDRESS,11,24,91,13,ES_UPPERCASE | ES_AUTOHSCROLL PUSHBUTTON "&PC",IDC_GOTOPC,11,40,15,13 PUSHBUTTON "&LR",IDC_GOTOLR,28,40,14,13 @@ -194,10 +194,10 @@ MENUITEM SEPARATOR END POPUP "&Emulation" BEGIN - MENUITEM "&Run\tF9", ID_EMULATION_RUN - MENUITEM "&Pause\tF10", ID_EMULATION_PAUSE + MENUITEM "&Run\tF7", ID_EMULATION_RUN + MENUITEM "&Pause\tF8", ID_EMULATION_PAUSE MENUITEM SEPARATOR - MENUITEM "R&eset\tF11", ID_EMULATION_RESET + MENUITEM "R&eset", ID_EMULATION_RESET MENUITEM SEPARATOR MENUITEM "&Interpreter", ID_CPU_INTERPRETER MENUITEM "&Slightly Faster Interpreter", ID_CPU_FASTINTERPRETER @@ -219,8 +219,8 @@ MENUITEM SEPARATOR MENUITEM "&Display Raw Framebuffer", ID_OPTIONS_DISPLAYRAWFRAMEBUFFER MENUITEM "&Buffered Rendering\tF5", ID_OPTIONS_BUFFEREDRENDERING MENUITEM "&Hardware Transform\tF6", ID_OPTIONS_HARDWARETRANSFORM - MENUITEM "&Linear Filtering\tF7", ID_OPTIONS_LINEARFILTERING - MENUITEM "&Fast Memory (dynarec, unstable)\tF8", ID_OPTIONS_FASTMEMORY + MENUITEM "&Linear Filtering", ID_OPTIONS_LINEARFILTERING + MENUITEM "&Fast Memory (dynarec, unstable)", ID_OPTIONS_FASTMEMORY MENUITEM "&Wireframe (experimental)", ID_OPTIONS_WIREFRAME MENUITEM "&Show Debug Statistics", ID_OPTIONS_SHOWDEBUGSTATISTICS MENUITEM SEPARATOR @@ -319,19 +319,16 @@ BEGIN "F", ID_DEBUG_MEMORYSEARCH, VIRTKEY, CONTROL, NOINVERT "M", ID_DEBUG_MEMORYVIEW, VIRTKEY, CONTROL, NOINVERT "R", ID_DEBUG_REGISTERS, VIRTKEY, CONTROL, NOINVERT - VK_F10, ID_EMULATION_PAUSE, VIRTKEY, NOINVERT - VK_F9, ID_EMULATION_RUN, VIRTKEY, NOINVERT - VK_F11, ID_EMULATION_RESET, VIRTKEY, NOINVERT + VK_F7, ID_EMULATION_RUN, VIRTKEY, NOINVERT + VK_F8, ID_EMULATION_PAUSE, VIRTKEY, NOINVERT VK_F2, ID_FILE_SAVESTATE, VIRTKEY, NOINVERT - VK_F4, ID_FILE_LOADSTATE, VIRTKEY, NOINVERT + VK_F4, ID_FILE_LOADSTATE, VIRTKEY, NOINVERT "1", ID_OPTIONS_SCREEN1X, VIRTKEY, CONTROL, NOINVERT "2", ID_OPTIONS_SCREEN2X, VIRTKEY, CONTROL, NOINVERT "3", ID_OPTIONS_SCREEN3X, VIRTKEY, CONTROL, NOINVERT "4", ID_OPTIONS_SCREEN4X, VIRTKEY, CONTROL, NOINVERT VK_F5, ID_OPTIONS_BUFFEREDRENDERING, VIRTKEY, NOINVERT - VK_F6, ID_OPTIONS_HARDWARETRANSFORM, VIRTKEY, NOINVERT - VK_F7,ID_OPTIONS_LINEARFILTERING, VIRTKEY, NOINVERT - VK_F8, ID_OPTIONS_FASTMEMORY, VIRTKEY, NOINVERT + VK_F6, ID_OPTIONS_HARDWARETRANSFORM, VIRTKEY, NOINVERT "W", ID_FILE_UNLOAD, VIRTKEY, CONTROL, NOINVERT VK_F12, ID_OPTIONS_FULLSCREEN, VIRTKEY, NOINVERT END From 0edbcdc955b6ccf1fced9debe83815b2c1bb51d6 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Dec 2012 02:56:27 -0800 Subject: [PATCH 11/89] Fix some missing things / bugs in save states. --- Core/Dialog/PSPMsgDialog.cpp | 1 + Core/Dialog/PSPOskDialog.cpp | 1 + Core/Dialog/PSPSaveDialog.cpp | 6 ++++- Core/Dialog/SavedataParam.cpp | 7 ++++++ Core/HLE/sceIo.cpp | 1 + Core/HLE/sceKernelMemory.cpp | 8 ++++++- Core/HLE/sceKernelVTimer.cpp | 41 +++++++++++++++++------------------ 7 files changed, 42 insertions(+), 23 deletions(-) diff --git a/Core/Dialog/PSPMsgDialog.cpp b/Core/Dialog/PSPMsgDialog.cpp index a5ef5ceb6e..f7e0dd79e2 100644 --- a/Core/Dialog/PSPMsgDialog.cpp +++ b/Core/Dialog/PSPMsgDialog.cpp @@ -208,6 +208,7 @@ int PSPMsgDialog::Shutdown() void PSPMsgDialog::DoState(PointerWrap &p) { + PSPDialog::DoState(p); p.Do(display); p.Do(messageDialog); p.Do(messageDialogAddr); diff --git a/Core/Dialog/PSPOskDialog.cpp b/Core/Dialog/PSPOskDialog.cpp index abe367b96e..00b539fc4b 100644 --- a/Core/Dialog/PSPOskDialog.cpp +++ b/Core/Dialog/PSPOskDialog.cpp @@ -236,6 +236,7 @@ int PSPOskDialog::Update() void PSPOskDialog::DoState(PointerWrap &p) { + PSPDialog::DoState(p); p.Do(oskParams); p.Do(oskData); p.Do(oskDesc); diff --git a/Core/Dialog/PSPSaveDialog.cpp b/Core/Dialog/PSPSaveDialog.cpp index 4c02582986..b9ee98b671 100644 --- a/Core/Dialog/PSPSaveDialog.cpp +++ b/Core/Dialog/PSPSaveDialog.cpp @@ -708,11 +708,15 @@ int PSPSaveDialog::Shutdown() void PSPSaveDialog::DoState(PointerWrap &p) { + PSPDialog::DoState(p); p.Do(display); param.DoState(p); p.Do(request); // Just reset it. - param.SetPspParam(&request); + bool hasParam = param.GetPspParam() != NULL; + p.Do(hasParam); + if (hasParam) + param.SetPspParam(&request); p.Do(requestAddr); p.Do(currentSelectedSave); p.Do(yesnoChoice); diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index 4abafe0c73..a0d23714ec 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -482,6 +482,7 @@ int SavedataParam::SetPspParam(SceUtilitySavedataParam *param) Clear(); saveDataList = new SaveFileInfo[1]; + saveDataListCount = 1; // get and stock file info for each file DEBUG_LOG(HLE,"Name : %s",GetSaveName(param).c_str()); @@ -608,6 +609,12 @@ void SavedataParam::DoState(PointerWrap &p) p.Do(selectedSave); p.Do(saveDataListCount); p.Do(saveNameListDataCount); + if (p.mode == p.MODE_READ) + { + if (saveDataList != NULL) + delete [] saveDataList; + saveDataList = new SaveFileInfo[saveDataListCount]; + } p.DoArray(saveDataList, saveDataListCount); p.DoMarker("SavedataParam"); } diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index a7f8e00564..c3b1386894 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -865,6 +865,7 @@ public: virtual void DoState(PointerWrap &p) { p.Do(name); + p.Do(index); // TODO: Is this the right way for it to wake up? int count = listing.size(); diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index 9ac86fc5ae..bce9a5cec3 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -55,6 +55,12 @@ struct NativeFPL //FPL - Fixed Length Dynamic Memory Pool - every item has the same length struct FPL : public KernelObject { + FPL() : blocks(NULL) {} + ~FPL() { + if (blocks != NULL) { + delete [] blocks; + } + } const char *GetName() {return nf.name;} const char *GetTypeName() {return "FPL";} static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_FPLID; } @@ -400,7 +406,7 @@ public: virtual void DoState(PointerWrap &p) { p.Do(address); - p.Do(name); + p.DoArray(name, sizeof(name)); p.DoMarker("PMB"); } diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index 35174f34f1..1d6fb67f89 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -23,25 +23,8 @@ // VTIMER ////////////////////////////////////////////////////////////////////////// -struct VTimer : public KernelObject +struct NativeVTimer { - const char *GetName() {return name;} - const char *GetTypeName() {return "VTimer";} - static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_VTID; } - int GetIDType() const { return SCE_KERNEL_TMID_VTimer; } - - virtual void DoState(PointerWrap &p) - { - p.Do(size); - p.Do(name); - p.Do(startTime); - p.Do(running); - p.Do(handler); - p.Do(handlerTime); - p.Do(argument); - p.DoMarker("VTimer"); - } - SceSize size; char name[KERNELOBJECT_MAX_NAME_LENGTH+1]; u64 startTime; @@ -51,6 +34,22 @@ struct VTimer : public KernelObject u32 argument; }; +struct VTimer : public KernelObject +{ + const char *GetName() {return nvt.name;} + const char *GetTypeName() {return "VTimer";} + static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_VTID; } + int GetIDType() const { return SCE_KERNEL_TMID_VTimer; } + + virtual void DoState(PointerWrap &p) + { + p.Do(nvt); + p.DoMarker("VTimer"); + } + + NativeVTimer nvt; +}; + KernelObject *__KernelVTimerObject() { return new VTimer; @@ -64,9 +63,9 @@ void sceKernelCreateVTimer() VTimer *vt = new VTimer(); SceUID uid = kernelObjects.Create(vt); - strncpy(vt->name, name, 32); - vt->running = true; - vt->startTime = 0; //TODO fix + strncpy(vt->nvt.name, name, 32); + vt->nvt.running = true; + vt->nvt.startTime = 0; //TODO fix RETURN(uid); //TODO: return timer ID } From 6d65be5626517a708b584b5391767984e9bbc7a7 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Dec 2012 03:34:11 -0800 Subject: [PATCH 12/89] Fix android build. --- android/jni/Android.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 22887307ff..51c17d5f74 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -68,6 +68,7 @@ LOCAL_SRC_FILES := \ $(SRC)/Common/Misc.cpp \ $(SRC)/Common/MathUtil.cpp \ $(SRC)/GPU/Math3D.cpp \ + $(SRC)/GPU/GPUCommon.cpp \ $(SRC)/GPU/GPUState.cpp \ $(SRC)/GPU/GeDisasm.cpp \ $(SRC)/GPU/GLES/Framebuffer.cpp \ From ea9f0be28a9e6d8a81a4287e206e423bc49f0216 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Dec 2012 11:41:33 -0800 Subject: [PATCH 13/89] Save more of the GPU's state, fix a crash. Well, ReapplyGfxState() seems kinda dangerous now... --- Core/HLE/sceGe.cpp | 2 ++ GPU/GLES/DisplayListInterpreter.cpp | 2 +- GPU/GPUCommon.cpp | 8 +++++++- GPU/GPUCommon.h | 1 + GPU/GPUInterface.h | 2 ++ 5 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceGe.cpp b/Core/HLE/sceGe.cpp index 7331d99d35..b12b695c62 100644 --- a/Core/HLE/sceGe.cpp +++ b/Core/HLE/sceGe.cpp @@ -33,9 +33,11 @@ void __GeDoState(PointerWrap &p) { p.Do(gstate); p.Do(gstate_c); + p.Do(gpuStats); ReapplyGfxState(); gpu->InvalidateCache(0, -1); + gpu->DoState(p); p.DoMarker("sceGe"); } diff --git a/GPU/GLES/DisplayListInterpreter.cpp b/GPU/GLES/DisplayListInterpreter.cpp index 1ca7c42e4d..bc02147ca4 100644 --- a/GPU/GLES/DisplayListInterpreter.cpp +++ b/GPU/GLES/DisplayListInterpreter.cpp @@ -1057,7 +1057,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { break; default: - DEBUG_LOG(G3D,"DL Unknown: %08x @ %08x", op, currentList->pc); + DEBUG_LOG(G3D,"DL Unknown: %08x @ %08x", op, currentList == NULL ? 0 : currentList->pc); break; } } diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 32ebb12465..725f5295a5 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -117,4 +117,10 @@ bool GPUCommon::ProcessDLQueue() void GPUCommon::PreExecuteOp(u32 op, u32 diff) { // Nothing to do -} \ No newline at end of file +} + +void GPUCommon::DoState(PointerWrap &p) { + p.Do(dlIdGenerator); + p.Do(dlQueue); + p.DoMarker("GPUCommon"); +} diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 03a31b1344..3bed056585 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -19,6 +19,7 @@ public: virtual void UpdateStall(int listid, u32 newstall); virtual u32 EnqueueList(u32 listpc, u32 stall, bool head); virtual int listStatus(int listid); + virtual void DoState(PointerWrap &p); protected: typedef std::deque DisplayListQueue; diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index ac45316451..19c2212d77 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -18,6 +18,7 @@ #pragma once #include "../Globals.h" +#include "../Common/ChunkFile.h" #include enum DisplayListStatus @@ -75,6 +76,7 @@ public: virtual void DeviceLost() = 0; virtual void Flush() = 0; + virtual void DoState(PointerWrap &p) = 0; // Debugging virtual void DumpNextFrame() = 0; From 589916fca292a47c8e5054ff4f177e85122daaa2 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Dec 2012 12:21:56 -0800 Subject: [PATCH 14/89] Move GPU state to sceDisplay, reset GPU on load. --- Core/HLE/sceDisplay.cpp | 15 ++++++++++++++- Core/HLE/sceGe.cpp | 8 +------- GPU/GLES/DisplayListInterpreter.cpp | 13 +++++++++++++ GPU/GLES/DisplayListInterpreter.h | 1 + 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index ddd793b43b..a217aaa258 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -109,7 +109,6 @@ void __DisplayInit() { vCount = 0; hCount = 0; hCountTotal = 0; - hasSetMode = false; lastFrameTime = 0; InitGfxState(); @@ -133,6 +132,20 @@ void __DisplayDoState(PointerWrap &p) { p.Do(leaveVblankEvent); CoreTiming::RestoreRegisterEvent(leaveVblankEvent, "LeaveVBlank", &hleLeaveVblank); + p.Do(gstate); + p.Do(gstate_c); + p.Do(gpuStats); + gpu->DoState(p); + + ReapplyGfxState(); + + if (p.mode == p.MODE_READ) { + if (hasSetMode) { + gpu->InitClear(); + } + gpu->SetDisplayFramebuffer(framebuf.topaddr, framebuf.pspFramebufLinesize, framebuf.pspFramebufFormat); + } + p.DoMarker("sceDisplay"); } diff --git a/Core/HLE/sceGe.cpp b/Core/HLE/sceGe.cpp index b12b695c62..08eda4ba9f 100644 --- a/Core/HLE/sceGe.cpp +++ b/Core/HLE/sceGe.cpp @@ -31,13 +31,7 @@ void __GeInit() void __GeDoState(PointerWrap &p) { - p.Do(gstate); - p.Do(gstate_c); - p.Do(gpuStats); - - ReapplyGfxState(); - gpu->InvalidateCache(0, -1); - gpu->DoState(p); + // Everything is done in sceDisplay. p.DoMarker("sceGe"); } diff --git a/GPU/GLES/DisplayListInterpreter.cpp b/GPU/GLES/DisplayListInterpreter.cpp index bc02147ca4..d5fd95edac 100644 --- a/GPU/GLES/DisplayListInterpreter.cpp +++ b/GPU/GLES/DisplayListInterpreter.cpp @@ -1120,3 +1120,16 @@ void GLES_GPU::InvalidateCache(u32 addr, int size) { void GLES_GPU::Flush() { transformDraw_.Flush(); } + +void GLES_GPU::DoState(PointerWrap &p) { + GPUCommon::DoState(p); + + TextureCache_Clear(true); + gstate_c.textureChanged = true; + for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter) { + fbo_destroy((*iter)->fbo); + delete (*iter); + } + vfbs_.clear(); + shaderManager_->ClearCache(true); +} diff --git a/GPU/GLES/DisplayListInterpreter.h b/GPU/GLES/DisplayListInterpreter.h index 70590c3c84..fbb7f46c21 100644 --- a/GPU/GLES/DisplayListInterpreter.h +++ b/GPU/GLES/DisplayListInterpreter.h @@ -53,6 +53,7 @@ public: virtual void DumpNextFrame(); virtual void Flush(); + virtual void DoState(PointerWrap &p); private: void DoBlockTransfer(); From 020f69e5fb7c74aedf2ffd08bcff3538e677212d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Dec 2012 12:33:40 -0800 Subject: [PATCH 15/89] Pause before browsing for a state file on Windows. --- Windows/WndMainWindow.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Windows/WndMainWindow.cpp b/Windows/WndMainWindow.cpp index c6f593a109..f6442f8315 100644 --- a/Windows/WndMainWindow.cpp +++ b/Windows/WndMainWindow.cpp @@ -313,6 +313,13 @@ namespace MainWindow break; case ID_FILE_LOADSTATE: + if (g_State.bEmuThreadStarted) + { + nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING; + for (int i=0; iGetDlgHandle(), WM_COMMAND, IDC_STOP, 0); + } if (W32Util::BrowseForFileName(true, hWnd, "Load state",0,"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0","ppst",fn)) { SetCursor(LoadCursor(0,IDC_WAIT)); @@ -321,6 +328,13 @@ namespace MainWindow break; case ID_FILE_SAVESTATE: + if (g_State.bEmuThreadStarted) + { + nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING; + for (int i=0; iGetDlgHandle(), WM_COMMAND, IDC_STOP, 0); + } if (W32Util::BrowseForFileName(false, hWnd, "Save state",0,"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0","ppst",fn)) { SetCursor(LoadCursor(0,IDC_WAIT)); @@ -780,6 +794,13 @@ namespace MainWindow if (!result) MessageBox(0, "Savestate failure. Please try again later.", "Sorry", MB_OK); SetCursor(LoadCursor(0, IDC_ARROW)); + + if (g_State.bEmuThreadStarted && nextState == CORE_RUNNING) + { + for (int i=0; iGetDlgHandle(), WM_COMMAND, IDC_GO, 0); + } } void SetNextState(CoreState state) From 848a2e2d2a8f9fdd940500aab8012b870ff1c4e8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Dec 2012 12:55:58 -0800 Subject: [PATCH 16/89] Arg, missed a crash in savedata for states. --- Core/Dialog/SavedataParam.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index a0d23714ec..77bf61317e 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -412,6 +412,7 @@ void SavedataParam::Clear() delete[] saveDataList; saveDataList = 0; + saveDataListCount = 0; } } From 8c98c7b1415f3094cc7d16bc447ea07e805efdd1 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Dec 2012 13:01:10 -0800 Subject: [PATCH 17/89] Reverse the analog Y for everyone. Verified XInput is still happy this way. --- Core/HLE/sceCtrl.cpp | 2 +- Windows/XinputDevice.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceCtrl.cpp b/Core/HLE/sceCtrl.cpp index 234bb3dc5f..d8998af521 100644 --- a/Core/HLE/sceCtrl.cpp +++ b/Core/HLE/sceCtrl.cpp @@ -163,7 +163,7 @@ void __CtrlSetAnalog(float x, float y) if (x < -1.0f) x = -1.0f; if (y < -1.0f) y = -1.0f; ctrlCurrent.analog[0] = (u8)(x * 127.f + 128.f); - ctrlCurrent.analog[1] = (u8)(y * 127.f + 128.f); + ctrlCurrent.analog[1] = (u8)(-y * 127.f + 128.f); } int __CtrlReadSingleBuffer(u32 ctrlDataPtr, bool negative) diff --git a/Windows/XinputDevice.cpp b/Windows/XinputDevice.cpp index 6f7687f49b..86fc0dab64 100644 --- a/Windows/XinputDevice.cpp +++ b/Windows/XinputDevice.cpp @@ -41,7 +41,7 @@ int XinputDevice::UpdateState() { if ( dwResult == ERROR_SUCCESS ) { this->ApplyDiff(state); Stick left = NormalizedDeadzoneFilter(state); - __CtrlSetAnalog(left.x, -left.y); + __CtrlSetAnalog(left.x, left.y); this->prevState = state; this->check_delay = 0; return 0; From 45c9ed389cb32314e682d050d4205fc6430bdc07 Mon Sep 17 00:00:00 2001 From: Xele02 Date: Sat, 29 Dec 2012 23:55:34 +0100 Subject: [PATCH 18/89] Implement mode 11 --- Core/Dialog/SavedataParam.cpp | 67 +++++++++++++++++++++++- Core/FileSystems/DirectoryFileSystem.cpp | 18 ++++++- 2 files changed, 83 insertions(+), 2 deletions(-) diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index a0d23714ec..d3c84772ae 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -75,6 +75,39 @@ namespace u8 key[16]; int sdkVersion; }; + + bool PSPMatch(std::string text, std::string regexp) + { + if(text.empty() && regexp.empty()) + return true; + else if(regexp == "*") + return true; + else if(text.empty()) + return false; + else if(regexp.empty()) + return false; + else if(regexp == "?" && text.length() == 1) + return true; + else if(text == regexp) + return true; + else if(regexp.data()[0] == '*') + { + bool res = PSPMatch(text.substr(1),regexp.substr(1)); + if(!res) + res = PSPMatch(text.substr(1),regexp); + return res; + } + else if(regexp.data()[0] == '?') + { + return PSPMatch(text.substr(1),regexp.substr(1)); + } + else if(regexp.data()[0] == text.data()[0]) + { + return PSPMatch(text.substr(1),regexp.substr(1)); + } + + return false; + } } SavedataParam::SavedataParam() @@ -394,7 +427,39 @@ bool SavedataParam::GetList(SceUtilitySavedataParam *param) if (Memory::IsValidAddress(param->idListAddr)) { - Memory::Write_U32(0,param->idListAddr+4); + u32 outputBuffer = Memory::Read_U32(param->idListAddr + 8); + u32 maxFile = Memory::Read_U32(param->idListAddr + 0); + + std::vector validDir; + std::vector allDir = pspFileSystem.GetDirListing(savePath); + + if (Memory::IsValidAddress(outputBuffer)) + { + std::string searchString = GetGameName(param)+GetSaveName(param); + for(int i = 0; i < allDir.size() && i < maxFile; i++) + { + std::string dirName = allDir[i].name; + if(PSPMatch(dirName, searchString)) + { + validDir.push_back(allDir[i]); + } + } + + for(int i = 0; i < validDir.size(); i++) + { + u32 baseAddr = outputBuffer + (i*72); + Memory::Write_U32(0x11FF,baseAddr + 0); // mode + Memory::Write_U64(0,baseAddr + 4); // TODO ctime << this seems to not work, write 0 only on 32bits + Memory::Write_U64(0,baseAddr + 20); // TODO atime + Memory::Write_U64(0,baseAddr + 36); // TODO mtime + // folder name without gamename (max 20 u8) + std::string outName = validDir[i].name.substr(GetGameName(param).size()); + Memory::Memset(baseAddr + 52,0,20); + Memory::Memcpy(baseAddr + 52, outName.c_str(), outName.size()); + } + } + // Save num of folder found + Memory::Write_U32(validDir.size(),param->idListAddr+4); } return true; } diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp index e57be86eb2..e742ebe255 100644 --- a/Core/FileSystems/DirectoryFileSystem.cpp +++ b/Core/FileSystems/DirectoryFileSystem.cpp @@ -541,7 +541,23 @@ std::vector DirectoryFileSystem::GetDirListing(std::string path) { break; } #else - ERROR_LOG(HLE, "GetDirListing not implemented on non-Windows"); + DIR *dp; + dirent *dirp; + if((dp = opendir(GetLocalPath(path).c_str())) == NULL) { + ERROR_LOG(HLE,"Error opening directory %s\n",path.c_str()); + return myVector; + } + + while ((dirp = readdir(dp)) != NULL) { + PSPFileInfo entry; + if(dirp->d_type == DT_DIR) + entry.type = FILETYPE_DIRECTORY; + else + entry.type = FILETYPE_NORMAL; + entry.name = dirp->d_name; + myVector.push_back(entry); + } + closedir(dp); #endif return myVector; } From 2ed0902ae25c31e39ccea1b4b6574528af6cf9f1 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 21 Dec 2012 22:11:44 -0800 Subject: [PATCH 19/89] Cleanup sceGe stubs and void return values. --- Core/HLE/sceGe.cpp | 67 +++++++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/Core/HLE/sceGe.cpp b/Core/HLE/sceGe.cpp index 08eda4ba9f..ca277b5856 100644 --- a/Core/HLE/sceGe.cpp +++ b/Core/HLE/sceGe.cpp @@ -87,12 +87,19 @@ u32 sceGeListEnQueueHead(u32 listAddress, u32 stallAddress, u32 callbackId, return listID; } -void sceGeListUpdateStallAddr(u32 displayListID, u32 stallAddress) +int sceGeListDeQueue(u32 listID) +{ + ERROR_LOG(HLE, "UNIMPL sceGeListDeQueue(%08x)", listID); + return 0; +} + +int sceGeListUpdateStallAddr(u32 displayListID, u32 stallAddress) { DEBUG_LOG(HLE, "sceGeListUpdateStallAddr(dlid=%i,stalladdr=%08x)", displayListID, stallAddress); gpu->UpdateStall(displayListID, stallAddress); + return 0; } int sceGeListSync(u32 displayListID, u32 mode) //0 : wait for completion 1:check and return @@ -113,19 +120,20 @@ u32 sceGeDrawSync(u32 mode) return 0; } -void sceGeContinue() +int sceGeContinue() { ERROR_LOG(HLE, "UNIMPL sceGeContinue"); // no arguments + return 0; } -void sceGeBreak(u32 mode) +int sceGeBreak(u32 mode) { //mode => 0 : current dlist 1: all drawing ERROR_LOG(HLE, "UNIMPL sceGeBreak(mode=%d)", mode); + return 0; } - u32 sceGeSetCallback(u32 structAddr) { DEBUG_LOG(HLE, "sceGeSetCallback(struct=%08x)", structAddr); @@ -150,10 +158,14 @@ u32 sceGeSetCallback(u32 structAddr) return 0; } -void sceGeUnsetCallback(u32 cbID) { +int sceGeUnsetCallback(u32 cbID) +{ DEBUG_LOG(HLE, "sceGeUnsetCallback(cbid=%08x)", cbID); + sceKernelReleaseSubIntrHandler(PSP_GE_INTR, PSP_GE_SUBINTR_FINISH); sceKernelReleaseSubIntrHandler(PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL); + + return 0; } // Points to 512 32-bit words, where we can probably layout the context however we want @@ -199,9 +211,16 @@ u32 sceGeRestoreContext(u32 ctxAddr) return 0; } -void sceGeGetMtx() +int sceGeGetMtx(int type, u32 matrixPtr) { - ERROR_LOG(HLE, "UNIMPL sceGeGetMtx()"); + ERROR_LOG(HLE, "UNIMPL sceGeGetMtx(%d, %08x)", type, matrixPtr); + return 0; +} + +u32 sceGeGetCmd(int cmd) +{ + ERROR_LOG(HLE, "UNIMPL sceGeGetCmd()"); + return 0; } u32 sceGeEdramSetAddrTranslation(int new_size) @@ -215,23 +234,23 @@ u32 sceGeEdramSetAddrTranslation(int new_size) const HLEFunction sceGe_user[] = { - {0xE47E40E4,&WrapU_V, "sceGeEdramGetAddr"}, - {0xAB49E76A,&WrapU_UUUU, "sceGeListEnQueue"}, - {0x1C0D95A6,&WrapU_UUUU, "sceGeListEnQueueHead"}, - {0xE0D68148,&WrapV_UU, "sceGeListUpdateStallAddr"}, - {0x03444EB4,&WrapI_UU, "sceGeListSync"}, - {0xB287BD61,&WrapU_U, "sceGeDrawSync"}, - {0xB448EC0D,&WrapV_U, "sceGeBreak"}, - {0x4C06E472,sceGeContinue, "sceGeContinue"}, - {0xA4FC06A4,&WrapU_U, "sceGeSetCallback"}, - {0x05DB22CE,&WrapV_U, "sceGeUnsetCallback"}, - {0x1F6752AD,&WrapU_V, "sceGeEdramGetSize"}, - {0xB77905EA,&WrapU_I,"sceGeEdramSetAddrTranslation"}, - {0xDC93CFEF,0,"sceGeGetCmd"}, - {0x57C8945B,&sceGeGetMtx,"sceGeGetMtx"}, - {0x438A385A,&WrapU_U,"sceGeSaveContext"}, - {0x0BF608FB,&WrapU_U,"sceGeRestoreContext"}, - {0x5FB86AB0,0,"sceGeListDeQueue"}, + {0xE47E40E4, WrapU_V, "sceGeEdramGetAddr"}, + {0xAB49E76A, WrapU_UUUU, "sceGeListEnQueue"}, + {0x1C0D95A6, WrapU_UUUU, "sceGeListEnQueueHead"}, + {0xE0D68148, WrapI_UU, "sceGeListUpdateStallAddr"}, + {0x03444EB4, WrapI_UU, "sceGeListSync"}, + {0xB287BD61, WrapU_U, "sceGeDrawSync"}, + {0xB448EC0D, WrapI_U, "sceGeBreak"}, + {0x4C06E472, WrapI_V, "sceGeContinue"}, + {0xA4FC06A4, WrapU_U, "sceGeSetCallback"}, + {0x05DB22CE, WrapI_U, "sceGeUnsetCallback"}, + {0x1F6752AD, WrapU_V, "sceGeEdramGetSize"}, + {0xB77905EA, WrapU_I, "sceGeEdramSetAddrTranslation"}, + {0xDC93CFEF, WrapU_I, "sceGeGetCmd"}, + {0x57C8945B, WrapI_IU, "sceGeGetMtx"}, + {0x438A385A, WrapU_U, "sceGeSaveContext"}, + {0x0BF608FB, WrapU_U, "sceGeRestoreContext"}, + {0x5FB86AB0, WrapI_U, "sceGeListDeQueue"}, }; void Register_sceGe_user() From 97bdaf5dd29dcc0766b9b4ac571320873f05821c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 21 Dec 2012 22:50:35 -0800 Subject: [PATCH 20/89] Add support for selecting the GE callback per list. Not sure if interrupts are right, but this should be more right. --- Core/HLE/FunctionWrappers.h | 5 ++ Core/HLE/sceGe.cpp | 92 ++++++++++++++++++++++------- Core/HLE/sceGe.h | 2 +- Core/HLE/sceKernel.h | 4 +- GPU/GLES/DisplayListInterpreter.cpp | 4 +- GPU/GLES/DisplayListInterpreter.h | 1 + GPU/GPUCommon.cpp | 3 +- GPU/GPUCommon.h | 2 +- GPU/GPUInterface.h | 3 +- GPU/Null/NullGpu.cpp | 4 +- 10 files changed, 90 insertions(+), 30 deletions(-) diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h index 2795e24c4f..4de18203a4 100644 --- a/Core/HLE/FunctionWrappers.h +++ b/Core/HLE/FunctionWrappers.h @@ -410,6 +410,11 @@ template void WrapU_UUUI() { RETURN(retval); } +template void WrapU_UUIU() { + u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); + RETURN(retval); +} + template void WrapU_UIII() { u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); RETURN(retval); diff --git a/Core/HLE/sceGe.cpp b/Core/HLE/sceGe.cpp index ca277b5856..80fe768c17 100644 --- a/Core/HLE/sceGe.cpp +++ b/Core/HLE/sceGe.cpp @@ -25,13 +25,19 @@ #include "../GPU/GPUState.h" #include "../GPU/GPUInterface.h" +static PspGeCallbackData ge_callback_data[16]; +static bool ge_used_callbacks[16] = {0}; + void __GeInit() { + memset(&ge_used_callbacks, 0, sizeof(ge_used_callbacks)); } void __GeDoState(PointerWrap &p) { - // Everything is done in sceDisplay. + p.DoArray(ge_callback_data, ARRAY_SIZE(ge_callback_data)); + p.DoArray(ge_used_callbacks, ARRAY_SIZE(ge_used_callbacks)); + // Everything else is done in sceDisplay. p.DoMarker("sceGe"); } @@ -57,7 +63,29 @@ u32 sceGeEdramGetSize() return retVal; } -u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, u32 callbackId, +// TODO: Probably shouldn't use an interrupt? +int __GeSubIntrBase(int callbackId) +{ + // Negative means don't use. + if (callbackId < 0) + return 0; + + if (callbackId >= ARRAY_SIZE(ge_used_callbacks)) + { + WARN_LOG(HLE, "Unexpected (too high) GE callback id %d, ignoring", callbackId); + return 0; + } + + if (!ge_used_callbacks[callbackId]) + { + WARN_LOG(HLE, "Unregistered GE callback id %d, ignoring", callbackId); + return 0; + } + + return (callbackId + 1) << 16; +} + +u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, int callbackId, u32 optParamAddr) { DEBUG_LOG(HLE, @@ -65,14 +93,14 @@ u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, u32 callbackId, listAddress, stallAddress, callbackId, optParamAddr); //if (!stallAddress) // stallAddress = listAddress; - u32 listID = gpu->EnqueueList(listAddress, stallAddress, false); + u32 listID = gpu->EnqueueList(listAddress, stallAddress, __GeSubIntrBase(callbackId), false); DEBUG_LOG(HLE, "List %i enqueued.", listID); //return display list ID return listID; } -u32 sceGeListEnQueueHead(u32 listAddress, u32 stallAddress, u32 callbackId, +u32 sceGeListEnQueueHead(u32 listAddress, u32 stallAddress, int callbackId, u32 optParamAddr) { DEBUG_LOG(HLE, @@ -80,7 +108,7 @@ u32 sceGeListEnQueueHead(u32 listAddress, u32 stallAddress, u32 callbackId, listAddress, stallAddress, callbackId, optParamAddr); //if (!stallAddress) // stallAddress = listAddress; - u32 listID = gpu->EnqueueList(listAddress, stallAddress, true); + u32 listID = gpu->EnqueueList(listAddress, stallAddress, __GeSubIntrBase(callbackId), true); DEBUG_LOG(HLE, "List %i enqueued.", listID); //return display list ID @@ -138,32 +166,54 @@ u32 sceGeSetCallback(u32 structAddr) { DEBUG_LOG(HLE, "sceGeSetCallback(struct=%08x)", structAddr); - PspGeCallbackData ge_callback_data; - Memory::ReadStruct(structAddr, &ge_callback_data); + int cbID = -1; + for (int i = 0; i < ARRAY_SIZE(ge_used_callbacks); ++i) + if (!ge_used_callbacks[i]) + { + cbID = i; + break; + } - if (ge_callback_data.finish_func) + if (cbID == -1) + return SCE_KERNEL_ERROR_OUT_OF_MEMORY; + + ge_used_callbacks[cbID] = true; + Memory::ReadStruct(structAddr, &ge_callback_data[cbID]); + + int subIntrBase = __GeSubIntrBase(cbID); + + if (ge_callback_data[cbID].finish_func) { - sceKernelRegisterSubIntrHandler(PSP_GE_INTR, PSP_GE_SUBINTR_FINISH, - ge_callback_data.finish_func, ge_callback_data.finish_arg); - sceKernelEnableSubIntr(PSP_GE_INTR, PSP_GE_SUBINTR_FINISH); + sceKernelRegisterSubIntrHandler(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_FINISH, + ge_callback_data[cbID].finish_func, ge_callback_data[cbID].finish_arg); + sceKernelEnableSubIntr(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_FINISH); } - if (ge_callback_data.signal_func) + if (ge_callback_data[cbID].signal_func) { - sceKernelRegisterSubIntrHandler(PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL, - ge_callback_data.signal_func, ge_callback_data.signal_arg); - sceKernelEnableSubIntr(PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL); + sceKernelRegisterSubIntrHandler(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_SIGNAL, + ge_callback_data[cbID].signal_func, ge_callback_data[cbID].signal_arg); + sceKernelEnableSubIntr(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_SIGNAL); } - // TODO: This should return a callback ID - return 0; + return cbID; } int sceGeUnsetCallback(u32 cbID) { DEBUG_LOG(HLE, "sceGeUnsetCallback(cbid=%08x)", cbID); - sceKernelReleaseSubIntrHandler(PSP_GE_INTR, PSP_GE_SUBINTR_FINISH); - sceKernelReleaseSubIntrHandler(PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL); + if (cbID >= ARRAY_SIZE(ge_used_callbacks)) + return SCE_KERNEL_ERROR_INVALID_ID; + + if (ge_used_callbacks[cbID]) + { + int subIntrBase = __GeSubIntrBase(cbID); + + sceKernelReleaseSubIntrHandler(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_FINISH); + sceKernelReleaseSubIntrHandler(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_SIGNAL); + } + + ge_used_callbacks[cbID] = false; return 0; } @@ -235,8 +285,8 @@ u32 sceGeEdramSetAddrTranslation(int new_size) const HLEFunction sceGe_user[] = { {0xE47E40E4, WrapU_V, "sceGeEdramGetAddr"}, - {0xAB49E76A, WrapU_UUUU, "sceGeListEnQueue"}, - {0x1C0D95A6, WrapU_UUUU, "sceGeListEnQueueHead"}, + {0xAB49E76A, WrapU_UUIU, "sceGeListEnQueue"}, + {0x1C0D95A6, WrapU_UUIU, "sceGeListEnQueueHead"}, {0xE0D68148, WrapI_UU, "sceGeListUpdateStallAddr"}, {0x03444EB4, WrapI_UU, "sceGeListSync"}, {0xB287BD61, WrapU_U, "sceGeDrawSync"}, diff --git a/Core/HLE/sceGe.h b/Core/HLE/sceGe.h index d6a19a0767..b37508a672 100644 --- a/Core/HLE/sceGe.h +++ b/Core/HLE/sceGe.h @@ -45,4 +45,4 @@ void __GeShutdown(); u32 sceGeRestoreContext(u32 ctxAddr); u32 sceGeSaveContext(u32 ctxAddr); -u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, u32 callbackId, u32 optParamAddr); +u32 sceGeListEnQueue(u32 listAddress, u32 stallAddress, int callbackId, u32 optParamAddr); diff --git a/Core/HLE/sceKernel.h b/Core/HLE/sceKernel.h index 90835442d1..08c373dfe6 100644 --- a/Core/HLE/sceKernel.h +++ b/Core/HLE/sceKernel.h @@ -23,7 +23,9 @@ enum { - SCE_KERNEL_ERROR_OK = 0, + SCE_KERNEL_ERROR_OK = 0, + SCE_KERNEL_ERROR_OUT_OF_MEMORY = 0x80000022, + SCE_KERNEL_ERROR_INVALID_ID = 0x80000100, SCE_KERNEL_ERROR_INVALID_VALUE = 0x800001fe, SCE_KERNEL_ERROR_INVALID_ARGUMENT = 0x800001ff, SCE_KERNEL_ERROR_ERROR = 0x80020001, diff --git a/GPU/GLES/DisplayListInterpreter.cpp b/GPU/GLES/DisplayListInterpreter.cpp index d5fd95edac..0c0ab11386 100644 --- a/GPU/GLES/DisplayListInterpreter.cpp +++ b/GPU/GLES/DisplayListInterpreter.cpp @@ -543,7 +543,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { case GE_CMD_FINISH: // TODO: Should this run while interrupts are suspended? if (interruptsEnabled_) - __TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, PSP_GE_SUBINTR_FINISH, 0); + __TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, currentList->subIntrBase | PSP_GE_SUBINTR_FINISH, 0); break; case GE_CMD_END: @@ -581,7 +581,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { } // TODO: Should this run while interrupts are suspended? if (interruptsEnabled_) - __TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL, signal); + __TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, currentList->subIntrBase | PSP_GE_SUBINTR_SIGNAL, signal); } break; case GE_CMD_FINISH: diff --git a/GPU/GLES/DisplayListInterpreter.h b/GPU/GLES/DisplayListInterpreter.h index fbb7f46c21..fdceb8a551 100644 --- a/GPU/GLES/DisplayListInterpreter.h +++ b/GPU/GLES/DisplayListInterpreter.h @@ -81,6 +81,7 @@ private: struct CmdProcessorState { u32 pc; u32 stallAddr; + int subIntrBase; }; struct VirtualFramebuffer { diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 725f5295a5..d439de6cb1 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -23,13 +23,14 @@ int GPUCommon::listStatus(int listid) return 0x80000100; // INVALID_ID } -u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, bool head) +u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, bool head) { DisplayList dl; dl.id = dlIdGenerator++; dl.pc = listpc & 0xFFFFFFF; dl.stall = stall & 0xFFFFFFF; dl.status = PSP_GE_LIST_QUEUED; + dl.subIntrBase = subIntrBase; if(head) dlQueue.push_front(dl); else diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 3bed056585..fbd55fd005 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -17,7 +17,7 @@ public: virtual bool InterpretList(DisplayList &list); virtual bool ProcessDLQueue(); virtual void UpdateStall(int listid, u32 newstall); - virtual u32 EnqueueList(u32 listpc, u32 stall, bool head); + virtual u32 EnqueueList(u32 listpc, u32 stall, int subIntrBase, bool head); virtual int listStatus(int listid); virtual void DoState(PointerWrap &p); diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 19c2212d77..94d0fc9d77 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -37,6 +37,7 @@ struct DisplayList u32 pc; u32 stall; DisplayListStatus status; + int subIntrBase; }; class GPUInterface @@ -49,7 +50,7 @@ public: // Draw queue management // TODO: Much of this should probably be shared between the different GPU implementations. - virtual u32 EnqueueList(u32 listpc, u32 stall, bool head) = 0; + virtual u32 EnqueueList(u32 listpc, u32 stall, int subIntrBase, bool head) = 0; virtual void UpdateStall(int listid, u32 newstall) = 0; virtual void DrawSync(int mode) = 0; virtual void Continue() = 0; diff --git a/GPU/Null/NullGpu.cpp b/GPU/Null/NullGpu.cpp index 8518704b7e..706caa616e 100644 --- a/GPU/Null/NullGpu.cpp +++ b/GPU/Null/NullGpu.cpp @@ -138,7 +138,7 @@ void NullGPU::ExecuteOp(u32 op, u32 diff) // TODO: Should this run while interrupts are suspended? if (interruptsEnabled_) - __TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, PSP_GE_SUBINTR_SIGNAL, signal); + __TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, currentList->subIntrBase | PSP_GE_SUBINTR_SIGNAL, signal); } break; @@ -170,7 +170,7 @@ void NullGPU::ExecuteOp(u32 op, u32 diff) DEBUG_LOG(G3D,"DL CMD FINISH"); // TODO: Should this run while interrupts are suspended? if (interruptsEnabled_) - __TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, PSP_GE_SUBINTR_FINISH, 0); + __TriggerInterruptWithArg(PSP_INTR_HLE, PSP_GE_INTR, currentList->subIntrBase | PSP_GE_SUBINTR_FINISH, 0); break; case GE_CMD_END: From 7bd16a7f979c8698577ab45ea6a30364b6c7af9e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 21 Dec 2012 23:08:17 -0800 Subject: [PATCH 21/89] Add warnings when GE callbacks are misused. --- Core/HLE/sceGe.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Core/HLE/sceGe.cpp b/Core/HLE/sceGe.cpp index 80fe768c17..a0caa81b15 100644 --- a/Core/HLE/sceGe.cpp +++ b/Core/HLE/sceGe.cpp @@ -175,7 +175,10 @@ u32 sceGeSetCallback(u32 structAddr) } if (cbID == -1) + { + WARN_LOG(HLE, "sceGeSetCallback(): out of callback ids"); return SCE_KERNEL_ERROR_OUT_OF_MEMORY; + } ge_used_callbacks[cbID] = true; Memory::ReadStruct(structAddr, &ge_callback_data[cbID]); @@ -203,7 +206,10 @@ int sceGeUnsetCallback(u32 cbID) DEBUG_LOG(HLE, "sceGeUnsetCallback(cbid=%08x)", cbID); if (cbID >= ARRAY_SIZE(ge_used_callbacks)) + { + WARN_LOG(HLE, "sceGeUnsetCallback(cbid=%08x): invalid callback id", cbID); return SCE_KERNEL_ERROR_INVALID_ID; + } if (ge_used_callbacks[cbID]) { @@ -212,6 +218,8 @@ int sceGeUnsetCallback(u32 cbID) sceKernelReleaseSubIntrHandler(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_FINISH); sceKernelReleaseSubIntrHandler(PSP_GE_INTR, subIntrBase | PSP_GE_SUBINTR_SIGNAL); } + else + WARN_LOG(HLE, "sceGeUnsetCallback(cbid=%08x): ignoring unregistered callback id", cbID); ge_used_callbacks[cbID] = false; From e3943c390a5606c339dbfe9612ae0aefa80ff0a7 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Dec 2012 16:13:37 -0800 Subject: [PATCH 22/89] Arg, I got these backwards. --- Windows/KeyboardDevice.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Windows/KeyboardDevice.cpp b/Windows/KeyboardDevice.cpp index 8d3cf30c37..dfbf67e39e 100644 --- a/Windows/KeyboardDevice.cpp +++ b/Windows/KeyboardDevice.cpp @@ -43,10 +43,10 @@ int KeyboardDevice::UpdateState() { switch (analog_ctrl_map[i + 1]) { case CTRL_UP: - analogY -= .8f; + analogY += .8f; break; case CTRL_DOWN: - analogY += .8f; + analogY -= .8f; break; case CTRL_LEFT: analogX -= .8f; From 03d9157d2654e01ed8b7126b542121d0b1550a0f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Dec 2012 19:36:03 -0800 Subject: [PATCH 23/89] Draw offscreen in headless (Windows only.) --- CMakeLists.txt | 2 +- Core/HLE/sceKernel.cpp | 10 +- headless/Headless.cpp | 50 ++++------ headless/Headless.vcxproj | 9 +- headless/Headless.vcxproj.filters | 5 + headless/StubHost.h | 53 +++++++++++ headless/WindowsHeadlessHost.cpp | 147 ++++++++++++++++++++++++++++++ headless/WindowsHeadlessHost.h | 44 +++++++++ 8 files changed, 279 insertions(+), 41 deletions(-) create mode 100644 headless/StubHost.h create mode 100644 headless/WindowsHeadlessHost.cpp create mode 100644 headless/WindowsHeadlessHost.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a44d5bef0..f6d109a56d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -886,7 +886,7 @@ if(WIN32) endif() if(HEADLESS) - add_executable(PPSSPPHeadless headless/Headless.cpp) + add_executable(PPSSPPHeadless headless/Headless.cpp headless/StubHost.h) target_link_libraries(PPSSPPHeadless ${CoreLibName} ${COCOA_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) setup_target_project(PPSSPPHeadless headless) diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index b590393c49..01df21da5d 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -182,20 +182,18 @@ bool __KernelIsRunning() { void sceKernelExitGame() { INFO_LOG(HLE,"sceKernelExitGame"); - if (PSP_CoreParameter().headLess) - exit(0); - else + if (!PSP_CoreParameter().headLess) PanicAlert("Game exited"); + __KernelSwitchOffThread("game exited"); Core_Stop(); } void sceKernelExitGameWithStatus() { INFO_LOG(HLE,"sceKernelExitGameWithStatus"); - if (PSP_CoreParameter().headLess) - exit(0); - else + if (!PSP_CoreParameter().headLess) PanicAlert("Game exited (with status)"); + __KernelSwitchOffThread("game exited"); Core_Stop(); } diff --git a/headless/Headless.cpp b/headless/Headless.cpp index dabd2586e7..aaeb2ae7d9 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -12,35 +12,13 @@ #include "../Core/Host.h" #include "Log.h" #include "LogManager.h" +#include "file/vfs.h" +#include "file/zip_read.h" -// TODO: Get rid of this junk -class HeadlessHost : public Host -{ -public: - // virtual void StartThread() - virtual void UpdateUI() {} - - virtual void UpdateMemView() {} - virtual void UpdateDisassembly() {} - - virtual void SetDebugMode(bool mode) { } - - virtual void InitGL() {} - virtual void BeginFrame() {} - virtual void EndFrame() {} - virtual void ShutdownGL() {} - - virtual void InitSound(PMixer *mixer) {} - virtual void UpdateSound() {} - virtual void ShutdownSound() {} - - // this is sent from EMU thread! Make sure that Host handles it properly! - virtual void BootDone() {} - virtual void PrepareShutdown() {} - - virtual bool IsDebuggingEnabled() {return false;} - virtual bool AttemptLoadSymbolMap() {return false;} -}; +#include "StubHost.h" +#ifdef _WIN32 +#include "WindowsHeadlessHost.h" +#endif class PrintfLogger : public LogListener { @@ -140,7 +118,12 @@ int main(int argc, const char* argv[]) return 1; } - host = new HeadlessHost(); + VFSRegister("", new DirectoryAssetReader("assets/")); + VFSRegister("", new DirectoryAssetReader("")); + + HeadlessHost *headlessHost = new HEADLESSHOST_CLASS(); + host = headlessHost; + host->InitGL(); LogManager::Init(); LogManager *logman = LogManager::GetInstance(); @@ -160,7 +143,7 @@ int main(int argc, const char* argv[]) coreParameter.mountIso = mountIso ? mountIso : ""; coreParameter.startPaused = false; coreParameter.cpuCore = useJit ? CPU_JIT : (fastInterpreter ? CPU_FASTINTERPRETER : CPU_INTERPRETER); - coreParameter.gpuCore = GPU_NULL; + coreParameter.gpuCore = headlessHost->isGLWorking() ? GPU_GLES : GPU_NULL; coreParameter.enableSound = false; coreParameter.headLess = true; coreParameter.printfEmuLog = true; @@ -191,10 +174,13 @@ int main(int argc, const char* argv[]) coreState = CORE_RUNNING; } - // NOTE: we won't get here until I've gotten rid of the exit(0) in sceExitProcess or whatever it's called - + host->ShutdownGL(); PSP_Shutdown(); + delete host; + host = NULL; + headlessHost = NULL; + if (autoCompare) { std::string expect_filename = std::string(bootFilename).substr(strlen(bootFilename - 4)) + ".expected"; diff --git a/headless/Headless.vcxproj b/headless/Headless.vcxproj index e4e8907ff7..3e58e022a8 100644 --- a/headless/Headless.vcxproj +++ b/headless/Headless.vcxproj @@ -81,7 +81,7 @@ Level3 Disabled WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - ../Common;..;../Core;../native/ext/glew; + ../Common;..;../Core;../native/ext/glew;../native Default @@ -112,7 +112,7 @@ true true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - ../Common;..;../Core;../native/ext/glew; + ../Common;..;../Core;../native/ext/glew;../native false StreamingSIMDExtensions2 Fast @@ -151,6 +151,7 @@ NotUsing NotUsing + @@ -175,6 +176,10 @@ {f761046e-6c38-4428-a5f1-38391a37bb34} + + + + diff --git a/headless/Headless.vcxproj.filters b/headless/Headless.vcxproj.filters index cb596797fd..5982bf35db 100644 --- a/headless/Headless.vcxproj.filters +++ b/headless/Headless.vcxproj.filters @@ -3,8 +3,13 @@ + + + + + \ No newline at end of file diff --git a/headless/StubHost.h b/headless/StubHost.h new file mode 100644 index 0000000000..5c9e4364fb --- /dev/null +++ b/headless/StubHost.h @@ -0,0 +1,53 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include "../Core/Host.h" + +#define HEADLESSHOST_CLASS HeadlessHost + +// TODO: Get rid of this junk +class HeadlessHost : public Host +{ +public: + // virtual void StartThread() + virtual void UpdateUI() {} + + virtual void UpdateMemView() {} + virtual void UpdateDisassembly() {} + + virtual void SetDebugMode(bool mode) { } + + virtual void InitGL() {} + virtual void BeginFrame() {} + virtual void EndFrame() {} + virtual void ShutdownGL() {} + + virtual void InitSound(PMixer *mixer) {} + virtual void UpdateSound() {} + virtual void ShutdownSound() {} + + // this is sent from EMU thread! Make sure that Host handles it properly + virtual void BootDone() {} + virtual void PrepareShutdown() {} + + virtual bool IsDebuggingEnabled() {return false;} + virtual bool AttemptLoadSymbolMap() {return false;} + + virtual bool isGLWorking() { return false; } +}; \ No newline at end of file diff --git a/headless/WindowsHeadlessHost.cpp b/headless/WindowsHeadlessHost.cpp new file mode 100644 index 0000000000..ce7086d41d --- /dev/null +++ b/headless/WindowsHeadlessHost.cpp @@ -0,0 +1,147 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "WindowsHeadlessHost.h" + +#include +#include + +#include "../native/gfx_es2/gl_state.h" +#include "../native/gfx/gl_common.h" + +const bool WINDOW_VISIBLE = false; +const int WINDOW_WIDTH = 480; +const int WINDOW_HEIGHT = 272; + +typedef BOOL (APIENTRY *PFNWGLSWAPINTERVALFARPROC)(int value); +PFNWGLSWAPINTERVALFARPROC wglSwapIntervalEXT = NULL; + +HWND CreateHiddenWindow() +{ + static WNDCLASSEX wndClass = { + sizeof(WNDCLASSEX), + CS_HREDRAW | CS_VREDRAW | CS_OWNDC, + DefWindowProc, + 0, + 0, + NULL, + NULL, + LoadCursor(NULL, IDC_ARROW), + (HBRUSH) GetStockObject(BLACK_BRUSH), + NULL, + "PPSSPPHeadless", + NULL, + }; + RegisterClassEx(&wndClass); + + DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP; + return CreateWindowEx(0, "PPSSPPHeadless", "PPSSPPHeadless", style, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, NULL, NULL); +} + +void SetVSync(int value) +{ + const char *extensions = (const char *) glGetString(GL_EXTENSIONS); + + if (!strstr(extensions, "WGL_EXT_swap_control")) + return; + + wglSwapIntervalEXT = (PFNWGLSWAPINTERVALFARPROC) wglGetProcAddress("wglSwapIntervalEXT"); + if (wglSwapIntervalEXT != NULL) + wglSwapIntervalEXT(value); +} + +void WindowsHeadlessHost::InitGL() +{ + glOkay = false; + hWnd = CreateHiddenWindow(); + + if (WINDOW_VISIBLE) + { + ShowWindow(hWnd, TRUE); + SetFocus(hWnd); + } + + int pixelFormat; + + static PIXELFORMATDESCRIPTOR pfd = {0}; + pfd.nSize = sizeof(pfd); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 32; + pfd.cDepthBits = 16; + pfd.iLayerType = PFD_MAIN_PLANE; + +#define ENFORCE(x, msg) { if (!(x)) { fprintf(stderr, msg); return; } } + + ENFORCE(hDC = GetDC(hWnd), "Unable to create DC."); + ENFORCE(pixelFormat = ChoosePixelFormat(hDC, &pfd), "Unable to match pixel format."); + ENFORCE(SetPixelFormat(hDC, pixelFormat, &pfd), "Unable to set pixel format."); + ENFORCE(hRC = wglCreateContext(hDC), "Unable to create GL context."); + ENFORCE(wglMakeCurrent(hDC, hRC), "Unable to activate GL context."); + + SetVSync(0); + + glewInit(); + glstate.Initialize(); + + if (ResizeGL()) + glOkay = true; +} + +void WindowsHeadlessHost::ShutdownGL() +{ + if (hRC) + { + wglMakeCurrent(NULL, NULL); + wglDeleteContext(hRC); + hRC = NULL; + } + + if (hDC) + ReleaseDC(hWnd, hDC); + hDC = NULL; + DestroyWindow(hWnd); + hWnd = NULL; +} + +bool WindowsHeadlessHost::ResizeGL() +{ + if (!hWnd) + return false; + + RECT rc; + GetWindowRect(hWnd, &rc); + + glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0.0f, WINDOW_WIDTH, WINDOW_HEIGHT, 0.0f, -1.0f, 1.0f); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + return true; +} + +void WindowsHeadlessHost::BeginFrame() +{ + +} + +void WindowsHeadlessHost::EndFrame() +{ + SwapBuffers(hDC); +} diff --git a/headless/WindowsHeadlessHost.h b/headless/WindowsHeadlessHost.h new file mode 100644 index 0000000000..2dc2b5b0b4 --- /dev/null +++ b/headless/WindowsHeadlessHost.h @@ -0,0 +1,44 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include "StubHost.h" + +#undef HEADLESSHOST_CLASS +#define HEADLESSHOST_CLASS WindowsHeadlessHost + +#include + +// TODO: Get rid of this junk +class WindowsHeadlessHost : public HeadlessHost +{ +public: + virtual void InitGL(); + virtual void BeginFrame(); + virtual void EndFrame(); + virtual void ShutdownGL(); + virtual bool isGLWorking() { return glOkay; } + +private: + bool ResizeGL(); + + bool glOkay; + HWND hWnd; + HDC hDC; + HGLRC hRC; +}; \ No newline at end of file From ade0f4103b3fd5b7829fd2103a88fa9d8579d663 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Dec 2012 20:49:45 -0800 Subject: [PATCH 24/89] Don't let native's log output spoil tests. Also, log to stderr, makes more sense anyway. --- Core/HLE/sceIo.cpp | 7 +++---- Core/Host.h | 3 +++ headless/Headless.cpp | 18 +++++++----------- headless/StubHost.h | 2 ++ headless/WindowsHeadlessHost.cpp | 31 +++++++++++++++++++++++++++++-- headless/WindowsHeadlessHost.h | 4 ++++ 6 files changed, 48 insertions(+), 17 deletions(-) diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index c3b1386894..ef817f557c 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -22,6 +22,7 @@ #include "../System.h" #include "../Config.h" +#include "../Host.h" #include "../SaveState.h" #include "HLE.h" #include "../MIPS/MIPS.h" @@ -644,10 +645,8 @@ u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 outPtr, std::string data(Memory::GetCharPointer(argAddr), argLen); if (PSP_CoreParameter().printfEmuLog) { - printf("%s", data.c_str()); -#ifdef _WIN32 - OutputDebugString(data.c_str()); -#endif + host->SendDebugOutput(data.c_str()); + // Also collect the debug output emuDebugOutput += data; } diff --git a/Core/Host.h b/Core/Host.h index 5600e01393..056395184c 100644 --- a/Core/Host.h +++ b/Core/Host.h @@ -60,6 +60,9 @@ public: virtual bool IsDebuggingEnabled() {return true;} virtual bool AttemptLoadSymbolMap() {return false;} virtual void SetWindowTitle(const char *message) {} + + // Used for headless. + virtual void SendDebugOutput(const std::string &output) {} }; extern Host *host; diff --git a/headless/Headless.cpp b/headless/Headless.cpp index aaeb2ae7d9..b4d0880b85 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -12,8 +12,6 @@ #include "../Core/Host.h" #include "Log.h" #include "LogManager.h" -#include "file/vfs.h" -#include "file/zip_read.h" #include "StubHost.h" #ifdef _WIN32 @@ -28,20 +26,20 @@ public: switch (level) { case LogTypes::LDEBUG: - printf("D %s", msg); + fprintf(stderr, "D %s", msg); break; case LogTypes::LINFO: - printf("I %s", msg); + fprintf(stderr, "I %s", msg); break; case LogTypes::LERROR: - printf("E %s", msg); + fprintf(stderr, "E %s", msg); break; case LogTypes::LWARNING: - printf("W %s", msg); + fprintf(stderr, "W %s", msg); break; case LogTypes::LNOTICE: default: - printf("N %s", msg); + fprintf(stderr, "N %s", msg); break; } } @@ -118,9 +116,6 @@ int main(int argc, const char* argv[]) return 1; } - VFSRegister("", new DirectoryAssetReader("assets/")); - VFSRegister("", new DirectoryAssetReader("")); - HeadlessHost *headlessHost = new HEADLESSHOST_CLASS(); host = headlessHost; host->InitGL(); @@ -160,8 +155,9 @@ int main(int argc, const char* argv[]) return 1; } - coreState = CORE_RUNNING; + host->BootDone(); + coreState = CORE_RUNNING; while (coreState == CORE_RUNNING) { // Run for a frame at a time, just because. diff --git a/headless/StubHost.h b/headless/StubHost.h index 5c9e4364fb..9445aee06c 100644 --- a/headless/StubHost.h +++ b/headless/StubHost.h @@ -49,5 +49,7 @@ public: virtual bool IsDebuggingEnabled() {return false;} virtual bool AttemptLoadSymbolMap() {return false;} + virtual void SendDebugOutput(const std::string &output) { printf("%s", output.c_str()); } + virtual bool isGLWorking() { return false; } }; \ No newline at end of file diff --git a/headless/WindowsHeadlessHost.cpp b/headless/WindowsHeadlessHost.cpp index ce7086d41d..dd473a8279 100644 --- a/headless/WindowsHeadlessHost.cpp +++ b/headless/WindowsHeadlessHost.cpp @@ -19,9 +19,13 @@ #include #include +#include -#include "../native/gfx_es2/gl_state.h" -#include "../native/gfx/gl_common.h" +#include "gfx_es2/gl_state.h" +#include "gfx/gl_common.h" +#include "gfx/gl_lost_manager.h" +#include "file/vfs.h" +#include "file/zip_read.h" const bool WINDOW_VISIBLE = false; const int WINDOW_WIDTH = 480; @@ -64,6 +68,27 @@ void SetVSync(int value) wglSwapIntervalEXT(value); } +void WindowsHeadlessHost::LoadNativeAssets() +{ + // Native is kinda talkative, but that's annoying in our case. + out = _fdopen(_dup(_fileno(stdout)), "wt"); + freopen("NUL", "wt", stdout); + + VFSRegister("", new DirectoryAssetReader("assets/")); + VFSRegister("", new DirectoryAssetReader("")); + VFSRegister("", new DirectoryAssetReader("../")); + + gl_lost_manager_init(); + + // See SendDebugOutput() for how things get back on track. +} + +void WindowsHeadlessHost::SendDebugOutput(const std::string &output) +{ + fprintf_s(out, "%s", output.c_str()); + OutputDebugString(output.c_str()); +} + void WindowsHeadlessHost::InitGL() { glOkay = false; @@ -99,6 +124,8 @@ void WindowsHeadlessHost::InitGL() glewInit(); glstate.Initialize(); + LoadNativeAssets(); + if (ResizeGL()) glOkay = true; } diff --git a/headless/WindowsHeadlessHost.h b/headless/WindowsHeadlessHost.h index 2dc2b5b0b4..28e51ee543 100644 --- a/headless/WindowsHeadlessHost.h +++ b/headless/WindowsHeadlessHost.h @@ -34,11 +34,15 @@ public: virtual void ShutdownGL(); virtual bool isGLWorking() { return glOkay; } + virtual void SendDebugOutput(const std::string &output); + private: bool ResizeGL(); + void LoadNativeAssets(); bool glOkay; HWND hWnd; HDC hDC; HGLRC hRC; + FILE *out; }; \ No newline at end of file From 1c8280b15e18bece273a005c7792bceb1f5706c4 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Dec 2012 21:01:13 -0800 Subject: [PATCH 25/89] Make graphics optional, it's slower to start. Might also be nice to batch tests. --- headless/Headless.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/headless/Headless.cpp b/headless/Headless.cpp index b4d0880b85..b0b3362a14 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -55,6 +55,12 @@ void printUsage(const char *progname, const char *reason) fprintf(stderr, "Options:\n"); fprintf(stderr, " -m, --mount umd.cso mount iso on umd:\n"); fprintf(stderr, " -l, --log full log output, not just emulated printfs\n"); + + HEADLESSHOST_CLASS h1; + HeadlessHost h2; + if (typeid(h1) != typeid(h2)) + fprintf(stderr, " --graphics use the full gpu backend (slower)\n"); + fprintf(stderr, " -f use the fast interpreter\n"); fprintf(stderr, " -j use jit (overrides -f)\n"); fprintf(stderr, " -c, --compare compare with output in file.expected\n"); @@ -67,6 +73,7 @@ int main(int argc, const char* argv[]) bool useJit = false; bool fastInterpreter = false; bool autoCompare = false; + bool useGraphics = false; const char *bootFilename = 0; const char *mountIso = 0; @@ -90,6 +97,8 @@ int main(int argc, const char* argv[]) fastInterpreter = true; else if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--compare")) autoCompare = true; + else if (!strcmp(argv[i], "--graphics")) + useGraphics = true; else if (bootFilename == 0) bootFilename = argv[i]; else @@ -116,7 +125,7 @@ int main(int argc, const char* argv[]) return 1; } - HeadlessHost *headlessHost = new HEADLESSHOST_CLASS(); + HeadlessHost *headlessHost = useGraphics ? new HEADLESSHOST_CLASS() : new HeadlessHost(); host = headlessHost; host->InitGL(); From 62b1fe0fb13abf16115d7ec64171bb313ea1cf49 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 30 Dec 2012 00:00:58 -0800 Subject: [PATCH 26/89] sceIo doesn't have to do emu output, headless can. --- Core/HLE/sceIo.cpp | 9 --------- Core/HLE/sceIo.h | 2 -- 2 files changed, 11 deletions(-) diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index ef817f557c..4f5ff5c8a4 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -78,12 +78,6 @@ typedef s32 SceMode; typedef s64 SceOff; typedef u64 SceIores; -std::string emuDebugOutput; - -const std::string &EmuDebugOutput() { - return emuDebugOutput; -} - typedef u32 (*DeferredAction)(SceUID id, int param); DeferredAction defAction = 0; u32 defParam = 0; @@ -646,9 +640,6 @@ u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 outPtr, if (PSP_CoreParameter().printfEmuLog) { host->SendDebugOutput(data.c_str()); - - // Also collect the debug output - emuDebugOutput += data; } else { diff --git a/Core/HLE/sceIo.h b/Core/HLE/sceIo.h index 0f87cde613..d05c00df06 100644 --- a/Core/HLE/sceIo.h +++ b/Core/HLE/sceIo.h @@ -29,5 +29,3 @@ KernelObject *__KernelDirListingObject(); void Register_IoFileMgrForUser(); void Register_StdioForUser(); - -const std::string &EmuDebugOutput(); From 2431112b397cf629bf21525b1838e71311be035c Mon Sep 17 00:00:00 2001 From: Florent Castelli Date: Sun, 30 Dec 2012 16:29:16 +0100 Subject: [PATCH 27/89] Update pspautotests --- pspautotests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pspautotests b/pspautotests index 5e5ae52067..f11966e358 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit 5e5ae520672b816943acabed1f223ebcd7cff16f +Subproject commit f11966e35825acce606f284f5485b21d6ea44c55 From b9408d30bd2c2ab5813ede7e8350296457623a0c Mon Sep 17 00:00:00 2001 From: Florent Castelli Date: Sun, 30 Dec 2012 16:35:51 +0100 Subject: [PATCH 28/89] Add gpu/displaylist/state to test list --- test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test.py b/test.py index 2e1248690b..9fb54bcb1c 100755 --- a/test.py +++ b/test.py @@ -60,6 +60,7 @@ tests_good = [ "misc/testgp", "string/string", "gpu/callbacks/ge_callbacks", + "gpu/displaylist/state", "threads/alarm/alarm", "threads/alarm/cancel/cancel", "threads/alarm/refer/refer", From e25822794519c611c9969f761998d9b54939d10e Mon Sep 17 00:00:00 2001 From: Florent Castelli Date: Sun, 30 Dec 2012 17:18:36 +0100 Subject: [PATCH 29/89] Fix Headless Windows project for x64 --- headless/Headless.vcxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/headless/Headless.vcxproj b/headless/Headless.vcxproj index 3e58e022a8..bc5cb35624 100644 --- a/headless/Headless.vcxproj +++ b/headless/Headless.vcxproj @@ -96,7 +96,7 @@ Level3 Disabled WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - ../Common;..;../Core;../native/ext/glew; + ../Common;..;../Core;../native/ext/glew;../native Console @@ -133,7 +133,7 @@ true true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - ../Common;..;../Core;../native/ext/glew; + ../Common;..;../Core;../native/ext/glew;../native Console From 1ea34bb6e83a3470995614fdb02a95280c9321b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 30 Dec 2012 21:30:33 +0100 Subject: [PATCH 30/89] Stub out all of VTimer. --- Core/HLE/FunctionWrappers.h | 20 ++++ Core/HLE/sceKernel.cpp | 30 ++--- Core/HLE/sceKernelThread.cpp | 7 +- Core/HLE/sceKernelThread.h | 46 ++++---- Core/HLE/sceKernelVTimer.cpp | 215 +++++++++++++++++++++++++++++------ Core/HLE/sceKernelVTimer.h | 17 ++- 6 files changed, 257 insertions(+), 78 deletions(-) diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h index 4de18203a4..6459ba6ab0 100644 --- a/Core/HLE/FunctionWrappers.h +++ b/Core/HLE/FunctionWrappers.h @@ -29,6 +29,12 @@ template void WrapU64_V() { currentMIPS->r[3] = (retval >> 32) & 0xFFFFFFFF; } +template void WrapU64_U() { + u64 retval = func(PARAM(0)); + currentMIPS->r[2] = retval & 0xFFFFFFFF; + currentMIPS->r[3] = (retval >> 32) & 0xFFFFFFFF; +} + template void WrapI_UU64() { u64 param_one = currentMIPS->r[6]; param_one |= (u64)(currentMIPS->r[7]) << 32; @@ -36,6 +42,13 @@ template void WrapI_UU64() { RETURN(retval); } +template void WrapU_UU64() { + u64 param_one = currentMIPS->r[6]; + param_one |= (u64)(currentMIPS->r[7]) << 32; + u32 retval = func(PARAM(0), param_one); + RETURN(retval); +} + template void WrapI_UUU64() { u64 param_two = currentMIPS->r[6]; param_two |= (u64)(currentMIPS->r[7]) << 32; @@ -50,6 +63,13 @@ template void WrapU_II64I() { RETURN(retval); } +template void WrapU_UU64UU() { + u64 param_one = currentMIPS->r[6]; + param_one |= (u64)(currentMIPS->r[7]) << 32; + u32 retval = func(PARAM(0), param_one, PARAM(4), PARAM(5)); + RETURN(retval); +} + template void WrapI64_II64I() { s64 param_one = currentMIPS->r[6]; param_one |= (s64)(currentMIPS->r[7]) << 32; diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index 01df21da5d..ad62a01ae7 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -527,21 +527,6 @@ const HLEFunction ThreadManForUser[] = {0x94416130,WrapU_UUUU,"sceKernelGetThreadmanIdList"}, {0x57CF62DD,WrapU_U,"sceKernelGetThreadmanIdType"}, - {0x20fff560,sceKernelCreateVTimer,"sceKernelCreateVTimer"}, - {0x328F9E52,0,"sceKernelDeleteVTimer"}, - {0xc68d9437,sceKernelStartVTimer,"sceKernelStartVTimer"}, - {0xD0AEEE87,0,"sceKernelStopVTimer"}, - {0xD2D615EF,0,"sceKernelCancelVTimerHandler"}, - {0xB3A59970,0,"sceKernelGetVTimerBase"}, - {0xB7C18B77,0,"sceKernelGetVTimerBaseWide"}, - {0x034A921F,0,"sceKernelGetVTimerTime"}, - {0xC0B3FFD2,0,"sceKernelGetVTimerTimeWide"}, - {0x5F32BEAA,0,"sceKernelReferVTimerStatus"}, - {0x542AD630,0,"sceKernelSetVTimerTime"}, - {0xFB6425C3,0,"sceKernelSetVTimerTimeWide"}, - {0xd8b299ae,sceKernelSetVTimerHandler,"sceKernelSetVTimerHandler"}, - {0x53B00E9A,0,"sceKernelSetVTimerHandlerWide"}, - {0x82BC5777,sceKernelGetSystemTimeWide,"sceKernelGetSystemTimeWide"}, {0xdb738f35,sceKernelGetSystemTime,"sceKernelGetSystemTime"}, {0x369ed59d,sceKernelGetSystemTimeLow,"sceKernelGetSystemTimeLow"}, @@ -615,6 +600,21 @@ const HLEFunction ThreadManForUser[] = {0xA8AA591F,sceKernelCancelFpl,"sceKernelCancelFpl"}, {0xD8199E4C,sceKernelReferFplStatus,"sceKernelReferFplStatus"}, + {0x20fff560,WrapU_CU,"sceKernelCreateVTimer"}, + {0x328F9E52,WrapU_U,"sceKernelDeleteVTimer"}, + {0xc68d9437,WrapU_U,"sceKernelStartVTimer"}, + {0xD0AEEE87,WrapU_U,"sceKernelStopVTimer"}, + {0xD2D615EF,WrapU_U,"sceKernelCancelVTimerHandler"}, + {0xB3A59970,WrapU_UU,"sceKernelGetVTimerBase"}, + {0xB7C18B77,WrapU64_U,"sceKernelGetVTimerBaseWide"}, + {0x034A921F,WrapU_UU,"sceKernelGetVTimerTime"}, + {0xC0B3FFD2,WrapU64_U,"sceKernelGetVTimerTimeWide"}, + {0x5F32BEAA,WrapU_UU,"sceKernelReferVTimerStatus"}, + {0x542AD630,WrapU_UU,"sceKernelSetVTimerTime"}, + {0xFB6425C3,WrapU_UU64,"sceKernelSetVTimerTimeWide"}, + {0xd8b299ae,WrapU_UUUU,"sceKernelSetVTimerHandler"}, + {0x53B00E9A,WrapU_UU64UU,"sceKernelSetVTimerHandlerWide"}, + // Not sure if these should be hooked up. See below. {0x0E927AED, _sceKernelReturnFromTimerHandler, "_sceKernelReturnFromTimerHandler"}, {0x532A522E, _sceKernelExitThread,"_sceKernelExitThread"}, diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index e791219d2b..70b86778b0 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -75,11 +75,6 @@ const char *waitTypeStrings[] = { "Ctrl", }; -struct SceKernelSysClock { - u32 low; - u32 hi; -}; - struct NativeCallback { SceUInt size; @@ -1225,7 +1220,7 @@ Thread *__KernelCreateThread(SceUID &id, SceUID moduleId, const char *name, u32 t->nt.numInterruptPreempts = 0; t->nt.numReleases = 0; t->nt.numThreadPreempts = 0; - t->nt.runForClocks.low = 0; + t->nt.runForClocks.lo = 0; t->nt.runForClocks.hi = 0; t->nt.wakeupCount = 0; if (moduleId) diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index b63fe58312..b3ca3cddb2 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -54,6 +54,11 @@ void sceKernelGetThreadExitStatus(); u32 sceKernelGetThreadmanIdType(u32); u32 sceKernelGetThreadmanIdList(u32 type, u32 readBufPtr, u32 readBufSize, u32 idCountPtr); +struct SceKernelSysClock { + u32 lo; + u32 hi; +}; + enum WaitType //probably not the real values { @@ -79,19 +84,19 @@ enum WaitType //probably not the real values struct ThreadContext { - void reset(); - u32 r[32]; - float f[32]; - float v[128]; - u32 vfpuCtrl[16]; + void reset(); + u32 r[32]; + float f[32]; + float v[128]; + u32 vfpuCtrl[16]; - u32 hi; - u32 lo; - u32 pc; - u32 fpcond; + u32 hi; + u32 lo; + u32 pc; + u32 fpcond; - u32 fcr0; - u32 fcr31; + u32 fcr0; + u32 fcr31; }; // Internal API, used by implementations of kernel functions @@ -126,15 +131,15 @@ void __KernelReSchedule(bool doCallbacks, const char *reason); // Registered callback types enum RegisteredCallbackType { - THREAD_CALLBACK_UMD = 0, - THREAD_CALLBACK_IO = 1, - THREAD_CALLBACK_MEMORYSTICK = 2, - THREAD_CALLBACK_MEMORYSTICK_FAT = 3, - THREAD_CALLBACK_POWER = 4, - THREAD_CALLBACK_EXIT = 5, - THREAD_CALLBACK_USER_DEFINED = 6, - THREAD_CALLBACK_SIZE = 7, - THREAD_CALLBACK_NUM_TYPES = 8, + THREAD_CALLBACK_UMD = 0, + THREAD_CALLBACK_IO = 1, + THREAD_CALLBACK_MEMORYSTICK = 2, + THREAD_CALLBACK_MEMORYSTICK_FAT = 3, + THREAD_CALLBACK_POWER = 4, + THREAD_CALLBACK_EXIT = 5, + THREAD_CALLBACK_USER_DEFINED = 6, + THREAD_CALLBACK_SIZE = 7, + THREAD_CALLBACK_NUM_TYPES = 8, }; // These operate on the current thread @@ -208,6 +213,7 @@ struct MipsCall { void DoState(PointerWrap &p); }; + enum ThreadStatus { THREADSTATUS_RUNNING = 1, diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index 1d6fb67f89..740735d060 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -16,33 +16,31 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "sceKernel.h" +#include "sceKernelThread.h" #include "sceKernelVTimer.h" #include "HLE.h" -////////////////////////////////////////////////////////////////////////// -// VTIMER -////////////////////////////////////////////////////////////////////////// +// Using INFO_LOG liberally when this is in development. When done, +// should be changed to DEBUG_LOG wherever applicable. -struct NativeVTimer -{ - SceSize size; - char name[KERNELOBJECT_MAX_NAME_LENGTH+1]; - u64 startTime; - bool running; - u32 handler; - u64 handlerTime; +struct NativeVTimer { + SceSize size; + char name[KERNELOBJECT_MAX_NAME_LENGTH+1]; + int running; + SceKernelSysClock basetime; + SceKernelSysClock curtime; + SceKernelSysClock scheduletime; + u32 handlerAddr; u32 argument; }; -struct VTimer : public KernelObject -{ +struct VTimer : public KernelObject { const char *GetName() {return nvt.name;} const char *GetTypeName() {return "VTimer";} static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_VTID; } int GetIDType() const { return SCE_KERNEL_TMID_VTimer; } - virtual void DoState(PointerWrap &p) - { + virtual void DoState(PointerWrap &p) { p.Do(nvt); p.DoMarker("VTimer"); } @@ -50,42 +48,191 @@ struct VTimer : public KernelObject NativeVTimer nvt; }; -KernelObject *__KernelVTimerObject() -{ +KernelObject *__KernelVTimerObject() { return new VTimer; } -void sceKernelCreateVTimer() -{ - DEBUG_LOG(HLE,"sceKernelCreateVTimer"); - const char *name = Memory::GetCharPointer(PARAM(0)); +u32 sceKernelCreateVTimer(const char *name, u32 optParamAddr) { + INFO_LOG(HLE,"sceKernelCreateVTimer(%s, %08x)", name, optParamAddr); VTimer *vt = new VTimer(); SceUID uid = kernelObjects.Create(vt); + memset(&vt->nvt, 0, sizeof(vt->nvt)); strncpy(vt->nvt.name, name, 32); - vt->nvt.running = true; - vt->nvt.startTime = 0; //TODO fix - RETURN(uid); //TODO: return timer ID + vt->nvt.running = 1; + return uid; //TODO: return timer ID } -void sceKernelStartVTimer() -{ - int timerID = PARAM(0); - DEBUG_LOG(HLE,"sceKernelStartVTimer(%i)", timerID); +u32 sceKernelDeleteVTimer(u32 uid) { + INFO_LOG(HLE,"sceKernelDeleteVTimer(%i)", uid); - RETURN(0); //ok; 1=alreadyrunning + u32 error; + VTimer *vt = kernelObjects.Get(uid, error); + if (!vt) { + return error; + } + // TODO: Deschedule events here. Might share code with Stop. + + return kernelObjects.Destroy(uid); } -void sceKernelSetVTimerHandler() -{ - DEBUG_LOG(HLE,"sceKernelSetVTimerHandler"); +u32 sceKernelStartVTimer(u32 uid) { + WARN_LOG(HLE,"FAKE sceKernelStartVTimer(%i)", uid); + u32 error; + VTimer *vt = kernelObjects.Get(uid, error); + if (!vt) { + return error; + } + if (vt->nvt.running) { + // Already running + return 1; + } else { + vt->nvt.running = 1; + // TODO: Schedule events etc. + return 0; + } +} + +u32 sceKernelStopVTimer(u32 uid) { + WARN_LOG(HLE,"FAKE sceKernelStartVTimer(%i)", uid); + u32 error; + VTimer *vt = kernelObjects.Get(uid, error); + if (!vt) { + return error; + } + if (vt->nvt.running) { + // Already running + return 0; + } else { + vt->nvt.running = 0; + // TODO: Deschedule events etc. + return 1; + } +} + +u32 sceKernelSetVTimerHandler(u32 uid, u32 scheduleAddr, u32 handlerFuncAddr, u32 commonAddr) { + ERROR_LOG(HLE,"UNIMPL sceKernelSetVTimerHandler(%i, %08x, %08x, %08x)", + uid, scheduleAddr, handlerFuncAddr, commonAddr); + u32 error; + VTimer *vt = kernelObjects.Get(uid, error); + if (!vt) { + return error; + } + // TODO + return 0; +} + +u32 sceKernelSetVTimerHandlerWide(u32 uid, u64 schedule, u32 handlerFuncAddr, u32 commonAddr) { + ERROR_LOG(HLE,"UNIMPL sceKernelSetVTimerHandlerWide(%i, %llu, %08x, %08x)", + uid, schedule, handlerFuncAddr, commonAddr); + u32 error; + VTimer *vt = kernelObjects.Get(uid, error); + if (!vt) { + return error; + } + // TODO + return 0; +} + +u32 sceKernelCancelVTimerHandler(u32 uid) { + ERROR_LOG(HLE,"UNIMPL sceKernelCancelVTimerHandler(%i)", uid); + u32 error; + VTimer *vt = kernelObjects.Get(uid, error); + if (!vt) { + return error; + } + // TODO + return 0; +} + +u32 sceKernelReferVTimerStatus(u32 uid, u32 statusAddr) { + INFO_LOG(HLE,"sceKernelReferVTimerStatus(%i, %08x)", uid, statusAddr); + u32 error; + VTimer *vt = kernelObjects.Get(uid, error); + if (!vt) { + return error; + } + // TODO: possibly update time values here? + Memory::WriteStruct(statusAddr, &vt->nvt); + return 0; +} + +u32 sceKernelGetVTimerBase(u32 uid, u32 baseClockAddr) { + INFO_LOG(HLE,"sceKernelGetVTimerBase(%i, %08x)", uid, baseClockAddr); + u32 error; + VTimer *vt = kernelObjects.Get(uid, error); + if (!vt) { + return error; + } + Memory::WriteStruct(baseClockAddr, &vt->nvt.basetime); + return 0; +} + +u64 sceKernelGetVTimerBaseWide(u32 uid) { + INFO_LOG(HLE,"sceKernelGetVTimerWide(%i)", uid); + u32 error; + VTimer *vt = kernelObjects.Get(uid, error); + if (!vt) { + return error; + } + // TODO: probably update the timer somehow? + u64 t = vt->nvt.curtime.lo; + t |= (u64)(vt->nvt.curtime.hi) << 32; + return t; +} + +u32 sceKernelGetVTimerTime(u32 uid, u32 timeClockAddr) { + INFO_LOG(HLE,"sceKernelGetVTimerTime(%i, %08x)", uid, timeClockAddr); + u32 error; + VTimer *vt = kernelObjects.Get(uid, error); + if (!vt) { + return error; + } + // TODO: probably update the timer somehow? + Memory::WriteStruct(timeClockAddr, &vt->nvt.curtime); + return 0; +} + +u64 sceKernelGetVTimerTimeWide(u32 uid) { + INFO_LOG(HLE,"sceKernelGetVTimerTimeWide(%i)", uid); + u32 error; + VTimer *vt = kernelObjects.Get(uid, error); + if (!vt) { + return error; + } + // TODO: probably update the timer somehow? + u64 t = vt->nvt.curtime.lo; + t |= (u64)(vt->nvt.curtime.hi) << 32; + return t; +} + +u32 sceKernelSetVTimerTime(u32 uid, u32 timeClockAddr) { + INFO_LOG(HLE,"sceKernelSetVTimerTime(%i, %08x)", uid, timeClockAddr); + u32 error; + VTimer *vt = kernelObjects.Get(uid, error); + if (!vt) { + return error; + } + Memory::ReadStruct(timeClockAddr, &vt->nvt.curtime); + return 0; +} + +u32 sceKernelSetVTimerTimeWide(u32 uid, u64 timeClock) { + INFO_LOG(HLE,"sceKernelSetVTimerTime(%i, %llu)", uid, timeClock); + u32 error; + VTimer *vt = kernelObjects.Get(uid, error); + if (!vt) { + return error; + } + vt->nvt.curtime.lo = timeClock & 0xFFFFFFFF; + vt->nvt.curtime.hi = timeClock >> 32; + return 0; } // Not sure why this is exposed... void _sceKernelReturnFromTimerHandler() { - DEBUG_LOG(HLE,"_sceKernelReturnFromTimerHandler"); - + ERROR_LOG(HLE,"_sceKernelReturnFromTimerHandler - should not be called!"); } diff --git a/Core/HLE/sceKernelVTimer.h b/Core/HLE/sceKernelVTimer.h index 3597dfeb18..9cde7913e5 100644 --- a/Core/HLE/sceKernelVTimer.h +++ b/Core/HLE/sceKernelVTimer.h @@ -17,9 +17,20 @@ #pragma once -void sceKernelCreateVTimer(); -void sceKernelStartVTimer(); -void sceKernelSetVTimerHandler(); +u32 sceKernelCreateVTimer(const char *name, u32 optParamAddr); +u32 sceKernelDeleteVTimer(u32 uid); +u32 sceKernelStartVTimer(u32 uid); +u32 sceKernelStopVTimer(u32 uid); +u32 sceKernelSetVTimerHandler(u32 uid, u32 scheduleAddr, u32 handlerFuncAddr, u32 commonAddr); +u32 sceKernelSetVTimerHandlerWide(u32 uid, u64 schedule, u32 handlerFuncAddr, u32 commonAddr); +u32 sceKernelCancelVTimerHandler(u32 uid); +u32 sceKernelReferVTimerStatus(u32 uid, u32 statusAddr); +u32 sceKernelGetVTimerBase(u32 uid, u32 baseClockAddr); //SceKernelSysClock +u64 sceKernelGetVTimerBaseWide(u32 uid); +u32 sceKernelGetVTimerTime(u32 uid, u32 timeClockAddr); +u64 sceKernelGetVTimerTimeWide(u32 uid); +u32 sceKernelSetVTimerTime(u32 uid, u32 timeClockAddr); +u32 sceKernelSetVTimerTimeWide(u32 uid, u64 timeClock); // TODO void _sceKernelReturnFromTimerHandler(); From 4a00bbbc33e8c88a0596b69b7a14d8f19ccb59dd Mon Sep 17 00:00:00 2001 From: raven02 Date: Mon, 31 Dec 2012 17:12:14 +0800 Subject: [PATCH 31/89] Add sceKernelSetCompiledSdkVersion500_505/507 --- Core/HLE/sceKernelMemory.cpp | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index bce9a5cec3..859c62c43e 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -595,6 +595,41 @@ void sceKernelSetCompiledSdkVersion600_602(int sdkVersion) return; } +void sceKernelSetCompiledSdkVersion500_505(int sdkVersion) +{ + int sdkMainVersion = sdkVersion & 0xFFFF0000; + if(sdkMainVersion == 0x5000000 + || sdkMainVersion == 0x5010000 + || sdkMainVersion == 0x5020000 + || sdkMainVersion == 0x5030000 + || sdkMainVersion == 0x5040000 + || sdkMainVersion == 0x5050000) + { + sdkVersion_ = sdkVersion; + flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION; + } + else + { + ERROR_LOG(HLE,"sceKernelSetCompiledSdkVersion500_505 unknown SDK : %x\n",sdkVersion); + } + return; +} + +void sceKernelSetCompiledSdkVersion507(int sdkVersion) +{ + int sdkMainVersion = sdkVersion & 0xFFFF0000; + if(sdkMainVersion == 0x5070000) + { + sdkVersion_ = sdkVersion; + flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION; + } + else + { + ERROR_LOG(HLE,"sceKernelSetCompiledSdkVersion507 unknown SDK : %x\n",sdkVersion); + } + return; +} + void sceKernelSetCompiledSdkVersion603_605(int sdkVersion) { int sdkMainVersion = sdkVersion & 0xFFFF0000; @@ -886,6 +921,8 @@ const HLEFunction SysMemUserForUser[] = { {0x315AD3A0,&WrapV_I,"sceKernelSetCompiledSdkVersion380_390"}, {0xEBD5C3E6,&WrapV_I,"sceKernelSetCompiledSdkVersion395"}, {0xf77d77cb,&WrapV_I,"sceKernelSetCompilerVersion"}, + {0x91de343c,&WrapV_I,"sceKernelSetCompiledSdkVersion500_505"}, + {0x7893f79a,&WrapV_I,"sceKernelSetCompiledSdkVersion507"}, {0x35669d4c,&WrapV_I,"sceKernelSetCompiledSdkVersion600_602"}, //?? {0x1b4217bc,&WrapV_I,"sceKernelSetCompiledSdkVersion603_605"}, {0x358ca1bb,&WrapV_I,"sceKernelSetCompiledSdkVersion606"}, From cff6d155f10bd0fbf2d7eb36437352098aea0f91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 31 Dec 2012 12:18:13 +0100 Subject: [PATCH 32/89] Add a null check. Make vtimer log ERROR until it works. --- Core/HLE/sceKernelVTimer.cpp | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/Core/HLE/sceKernelVTimer.cpp b/Core/HLE/sceKernelVTimer.cpp index 740735d060..22a4dd8884 100644 --- a/Core/HLE/sceKernelVTimer.cpp +++ b/Core/HLE/sceKernelVTimer.cpp @@ -20,7 +20,7 @@ #include "sceKernelVTimer.h" #include "HLE.h" -// Using INFO_LOG liberally when this is in development. When done, +// Using ERROR_LOG liberally when this is in development. When done, // should be changed to DEBUG_LOG wherever applicable. struct NativeVTimer { @@ -53,19 +53,20 @@ KernelObject *__KernelVTimerObject() { } u32 sceKernelCreateVTimer(const char *name, u32 optParamAddr) { - INFO_LOG(HLE,"sceKernelCreateVTimer(%s, %08x)", name, optParamAddr); + ERROR_LOG(HLE,"FAKE sceKernelCreateVTimer(%s, %08x)", name, optParamAddr); VTimer *vt = new VTimer(); SceUID uid = kernelObjects.Create(vt); memset(&vt->nvt, 0, sizeof(vt->nvt)); - strncpy(vt->nvt.name, name, 32); + if (name) + strncpy(vt->nvt.name, name, 32); vt->nvt.running = 1; return uid; //TODO: return timer ID } u32 sceKernelDeleteVTimer(u32 uid) { - INFO_LOG(HLE,"sceKernelDeleteVTimer(%i)", uid); + ERROR_LOG(HLE,"FAKE sceKernelDeleteVTimer(%i)", uid); u32 error; VTimer *vt = kernelObjects.Get(uid, error); @@ -78,7 +79,7 @@ u32 sceKernelDeleteVTimer(u32 uid) { } u32 sceKernelStartVTimer(u32 uid) { - WARN_LOG(HLE,"FAKE sceKernelStartVTimer(%i)", uid); + ERROR_LOG(HLE,"FAKE sceKernelStartVTimer(%i)", uid); u32 error; VTimer *vt = kernelObjects.Get(uid, error); @@ -96,7 +97,7 @@ u32 sceKernelStartVTimer(u32 uid) { } u32 sceKernelStopVTimer(u32 uid) { - WARN_LOG(HLE,"FAKE sceKernelStartVTimer(%i)", uid); + ERROR_LOG(HLE,"FAKE sceKernelStartVTimer(%i)", uid); u32 error; VTimer *vt = kernelObjects.Get(uid, error); if (!vt) { @@ -148,7 +149,7 @@ u32 sceKernelCancelVTimerHandler(u32 uid) { } u32 sceKernelReferVTimerStatus(u32 uid, u32 statusAddr) { - INFO_LOG(HLE,"sceKernelReferVTimerStatus(%i, %08x)", uid, statusAddr); + ERROR_LOG(HLE,"sceKernelReferVTimerStatus(%i, %08x)", uid, statusAddr); u32 error; VTimer *vt = kernelObjects.Get(uid, error); if (!vt) { @@ -160,7 +161,7 @@ u32 sceKernelReferVTimerStatus(u32 uid, u32 statusAddr) { } u32 sceKernelGetVTimerBase(u32 uid, u32 baseClockAddr) { - INFO_LOG(HLE,"sceKernelGetVTimerBase(%i, %08x)", uid, baseClockAddr); + ERROR_LOG(HLE,"sceKernelGetVTimerBase(%i, %08x)", uid, baseClockAddr); u32 error; VTimer *vt = kernelObjects.Get(uid, error); if (!vt) { @@ -171,7 +172,7 @@ u32 sceKernelGetVTimerBase(u32 uid, u32 baseClockAddr) { } u64 sceKernelGetVTimerBaseWide(u32 uid) { - INFO_LOG(HLE,"sceKernelGetVTimerWide(%i)", uid); + ERROR_LOG(HLE,"sceKernelGetVTimerWide(%i)", uid); u32 error; VTimer *vt = kernelObjects.Get(uid, error); if (!vt) { @@ -184,7 +185,7 @@ u64 sceKernelGetVTimerBaseWide(u32 uid) { } u32 sceKernelGetVTimerTime(u32 uid, u32 timeClockAddr) { - INFO_LOG(HLE,"sceKernelGetVTimerTime(%i, %08x)", uid, timeClockAddr); + ERROR_LOG(HLE,"sceKernelGetVTimerTime(%i, %08x)", uid, timeClockAddr); u32 error; VTimer *vt = kernelObjects.Get(uid, error); if (!vt) { @@ -196,7 +197,7 @@ u32 sceKernelGetVTimerTime(u32 uid, u32 timeClockAddr) { } u64 sceKernelGetVTimerTimeWide(u32 uid) { - INFO_LOG(HLE,"sceKernelGetVTimerTimeWide(%i)", uid); + ERROR_LOG(HLE,"sceKernelGetVTimerTimeWide(%i)", uid); u32 error; VTimer *vt = kernelObjects.Get(uid, error); if (!vt) { @@ -209,7 +210,7 @@ u64 sceKernelGetVTimerTimeWide(u32 uid) { } u32 sceKernelSetVTimerTime(u32 uid, u32 timeClockAddr) { - INFO_LOG(HLE,"sceKernelSetVTimerTime(%i, %08x)", uid, timeClockAddr); + ERROR_LOG(HLE,"sceKernelSetVTimerTime(%i, %08x)", uid, timeClockAddr); u32 error; VTimer *vt = kernelObjects.Get(uid, error); if (!vt) { @@ -220,7 +221,7 @@ u32 sceKernelSetVTimerTime(u32 uid, u32 timeClockAddr) { } u32 sceKernelSetVTimerTimeWide(u32 uid, u64 timeClock) { - INFO_LOG(HLE,"sceKernelSetVTimerTime(%i, %llu)", uid, timeClock); + ERROR_LOG(HLE,"sceKernelSetVTimerTime(%i, %llu)", uid, timeClock); u32 error; VTimer *vt = kernelObjects.Get(uid, error); if (!vt) { From ca4c767d3851c3c45207aba9f81c9d9f1a1c60f1 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 31 Dec 2012 15:39:49 -0800 Subject: [PATCH 33/89] Fix mistake from savestates breaking saving. Clear after, not first. Was killing the count. --- Core/Dialog/SavedataParam.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index 54d32fef4e..52afb9c19f 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -500,6 +500,8 @@ int SavedataParam::SetPspParam(SceUtilitySavedataParam *param) char (*saveNameListData)[20]; if (param->saveNameList != 0) { + Clear(); + saveNameListData = (char(*)[20])Memory::GetPointer(param->saveNameList); // Get number of fileName in array @@ -509,7 +511,6 @@ int SavedataParam::SetPspParam(SceUtilitySavedataParam *param) saveDataListCount++; } while(saveNameListData[saveDataListCount][0] != 0); - Clear(); saveDataList = new SaveFileInfo[saveDataListCount]; // get and stock file info for each file From cd8ba8495d20c107ceda5bc5cd4061a410cb5a48 Mon Sep 17 00:00:00 2001 From: Xele02 Date: Mon, 31 Dec 2012 19:08:46 +0100 Subject: [PATCH 34/89] Update mode 8 Add mode 12, 13, 17, 22 --- Core/Dialog/PSPSaveDialog.cpp | 50 +++++-- Core/Dialog/SavedataParam.cpp | 252 +++++++++++++++++++++++----------- Core/Dialog/SavedataParam.h | 23 ++-- 3 files changed, 231 insertions(+), 94 deletions(-) diff --git a/Core/Dialog/PSPSaveDialog.cpp b/Core/Dialog/PSPSaveDialog.cpp index b9ee98b671..05afc27d54 100644 --- a/Core/Dialog/PSPSaveDialog.cpp +++ b/Core/Dialog/PSPSaveDialog.cpp @@ -81,9 +81,12 @@ int PSPSaveDialog::Init(int paramAddr) display = DS_DELETE_LIST_CHOICE; break; case SCE_UTILITY_SAVEDATA_TYPE_SIZES: - display = DS_NONE; - break; case SCE_UTILITY_SAVEDATA_TYPE_LIST: + case SCE_UTILITY_SAVEDATA_TYPE_FILES: + case SCE_UTILITY_SAVEDATA_TYPE_SIZES22: + case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE: + case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE: + case SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE: display = DS_NONE; break; case SCE_UTILITY_SAVEDATA_TYPE_DELETE: // This run on PSP display a list of all save on the PSP. Weird. (Not really, it's to let you free up space) @@ -242,7 +245,7 @@ void PSPSaveDialog::DisplaySaveDataInfo1() char txt[2048]; _dbg_assert_msg_(HLE, sizeof(txt) > sizeof(SaveFileInfo), "Local buffer is too small."); - sprintf(txt,"%s\n%02d/%02d/%d %02d:%02d %lld KB\n%s\n%s" + snprintf(txt,2048,"%s\n%02d/%02d/%d %02d:%02d %lld KB\n%s\n%s" , param.GetFileInfo(currentSelectedSave).title , param.GetFileInfo(currentSelectedSave).modif_time.tm_mday , param.GetFileInfo(currentSelectedSave).modif_time.tm_mon + 1 @@ -266,7 +269,7 @@ void PSPSaveDialog::DisplaySaveDataInfo2() else { char txt[1024]; - sprintf(txt,"%s\n%02d/%02d/%d %02d:%02d\n%lld KB" + snprintf(txt,1024,"%s\n%02d/%02d/%d %02d:%02d\n%lld KB" , param.GetFileInfo(currentSelectedSave).saveTitle , param.GetFileInfo(currentSelectedSave).modif_time.tm_mday , param.GetFileInfo(currentSelectedSave).modif_time.tm_mon + 1 @@ -671,10 +674,41 @@ int PSPSaveDialog::Update() param.GetPspParam()->result = 0; status = SCE_UTILITY_STATUS_FINISHED; break; - // TODO: Don't know the name? - case 12: - // Pretend we have nothing, always. - param.GetPspParam()->result = SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA; + case SCE_UTILITY_SAVEDATA_TYPE_FILES: + if(param.GetFilesList(param.GetPspParam())) + { + param.GetPspParam()->result = 0; + } + else + { + param.GetPspParam()->result = SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA; + } + status = SCE_UTILITY_STATUS_FINISHED; + break; + case SCE_UTILITY_SAVEDATA_TYPE_SIZES22: + if(param.GetSizes22(param.GetPspParam())) + { + param.GetPspParam()->result = 0; + } + else + { + param.GetPspParam()->result = SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA; + } + status = SCE_UTILITY_STATUS_FINISHED; + break; + case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE: + case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE: + if(param.Save(param.GetPspParam(),param.GetSelectedSave())) + param.GetPspParam()->result = 0; + else + param.GetPspParam()->result = SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA; + status = SCE_UTILITY_STATUS_FINISHED; + break; + case SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE: + if(param.Load(param.GetPspParam(),param.GetSelectedSave())) + param.GetPspParam()->result = 0; + else + param.GetPspParam()->result = SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA; // not sure if correct code status = SCE_UTILITY_STATUS_FINISHED; break; default: diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index 52afb9c19f..315f13ba82 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -163,6 +163,8 @@ std::string SavedataParam::GetSaveName(SceUtilitySavedataParam* param) char saveName[21]; memcpy(saveName,param->saveName,20); saveName[20] = 0; + if(strcmp(saveName,"<>") == 0) + return ""; return saveName; } @@ -200,95 +202,129 @@ bool SavedataParam::Save(SceUtilitySavedataParam* param, int saveId) return false; } - u8 *data_ = (u8*)Memory::GetPointer(*((unsigned int*)¶m->dataBuf)); - std::string dirPath = GetSaveFilePath(param, saveId); if (!pspFileSystem.GetFileInfo(dirPath).exists) pspFileSystem.MkDir(dirPath); - std::string filePath = dirPath+"/"+GetFileName(param); - INFO_LOG(HLE,"Saving file with size %u in %s",param->dataBufSize,filePath.c_str()); - if (!WritePSPFile(filePath, data_, param->dataBufSize)) + if(param->dataBuf != 0) // Can launch save without save data in mode 13 { - ERROR_LOG(HLE,"Error writing file %s",filePath.c_str()); - return false; + std::string filePath = dirPath+"/"+GetFileName(param); + INFO_LOG(HLE,"Saving file with size %u in %s",param->dataBufSize,filePath.c_str()); + u8 *data_ = (u8*)Memory::GetPointer(param->dataBuf); + + if (!WritePSPFile(filePath, data_, param->dataBufSize)) + { + ERROR_LOG(HLE,"Error writing file %s",filePath.c_str()); + return false; + } } - else + + // SAVE PARAM.SFO + ParamSFOData sfoFile; + std::string sfopath = dirPath+"/"+sfoName; + PSPFileInfo sfoInfo = pspFileSystem.GetFileInfo(sfopath); + if(sfoInfo.exists) // Read old sfo if exist { - // SAVE PARAM.SFO - ParamSFOData sfoFile; - sfoFile.SetValue("TITLE",param->sfoParam.title,128); - sfoFile.SetValue("SAVEDATA_TITLE",param->sfoParam.savedataTitle,128); - sfoFile.SetValue("SAVEDATA_DETAIL",param->sfoParam.detail,1024); - sfoFile.SetValue("PARENTAL_LEVEL",param->sfoParam.parentalLevel,4); - sfoFile.SetValue("CATEGORY","MS",4); - sfoFile.SetValue("SAVEDATA_DIRECTORY",GetSaveDir(param,saveId),64); + u8 *sfoData = new u8[sfoInfo.size]; + size_t sfoSize = sfoInfo.size; + if(ReadPSPFile(sfopath,sfoData,sfoSize)) + { + sfoFile.ReadSFO(sfoData,sfoSize); + delete[] sfoData; + } + } - // For each file, 32 bytes for filename, 32 bytes for file hash (0 in PPSSPP) - u8* tmpData = new u8[3168]; + // Update values + sfoFile.SetValue("TITLE",param->sfoParam.title,128); + sfoFile.SetValue("SAVEDATA_TITLE",param->sfoParam.savedataTitle,128); + sfoFile.SetValue("SAVEDATA_DETAIL",param->sfoParam.detail,1024); + sfoFile.SetValue("PARENTAL_LEVEL",param->sfoParam.parentalLevel,4); + sfoFile.SetValue("CATEGORY","MS",4); + sfoFile.SetValue("SAVEDATA_DIRECTORY",GetSaveDir(param,saveId),64); + + // For each file, 13 bytes for filename, 16 bytes for file hash (0 in PPSSPP), 3 byte for padding + u8* tmpData = sfoFile.GetValueData("SAVEDATA_FILE_LIST", 0); + u8* tmpData2 = 0; + if(tmpData == 0) + { + tmpData2 = new u8[3168]; // 99 filename max + tmpData = tmpData2; memset(tmpData, 0, 3168); - sprintf((char*)tmpData,"%s",GetFileName(param).c_str()); - sfoFile.SetValue("SAVEDATA_FILE_LIST", tmpData, 3168, 3168); - delete[] tmpData; - - // No crypted save, so fill with 0 - tmpData = new u8[128]; - memset(tmpData, 0, 128); - sfoFile.SetValue("SAVEDATA_PARAMS", tmpData, 128, 128); - delete[] tmpData; - - u8 *sfoData; - size_t sfoSize; - sfoFile.WriteSFO(&sfoData,&sfoSize); - std::string sfopath = dirPath+"/"+sfoName; - WritePSPFile(sfopath, sfoData, sfoSize); - delete[] sfoData; - - // SAVE ICON0 - if (param->icon0FileData.buf) + } + if(param->dataBuf != 0) + { + char* fName = (char*)tmpData; + for(int i = 0; i < 99; i++) { - data_ = (u8*)Memory::GetPointer(*((unsigned int*)¶m->icon0FileData.buf)); - std::string icon0path = dirPath+"/"+icon0Name; - WritePSPFile(icon0path, data_, param->icon0FileData.bufSize); - } - // SAVE ICON1 - if (param->icon1FileData.buf) - { - data_ = (u8*)Memory::GetPointer(*((unsigned int*)¶m->icon1FileData.buf)); - std::string icon1path = dirPath+"/"+icon1Name; - WritePSPFile(icon1path, data_, param->icon1FileData.bufSize); - } - // SAVE PIC1 - if (param->pic1FileData.buf) - { - data_ = (u8*)Memory::GetPointer(*((unsigned int*)¶m->pic1FileData.buf)); - std::string pic1path = dirPath+"/"+pic1Name; - WritePSPFile(pic1path, data_, param->pic1FileData.bufSize); - } + if(fName[0] == 0) + break; // End of list + if(strncmp(fName,GetFileName(param).c_str(),20) == 0) + break; // File already in SFO - // Save SND - if (param->snd0FileData.buf) - { - data_ = (u8*)Memory::GetPointer(*((unsigned int*)¶m->snd0FileData.buf)); - std::string snd0path = dirPath+"/"+snd0Name; - WritePSPFile(snd0path, data_, param->snd0FileData.bufSize); + fName += 32; } + snprintf(fName, 20,"%s",GetFileName(param).c_str()); + } + sfoFile.SetValue("SAVEDATA_FILE_LIST", tmpData, 3168, 3168); + if(tmpData2) + delete[] tmpData2; - // Save Encryption Data - { - EncryptFileInfo encryptInfo; - int dataSize = sizeof(encryptInfo); // version + key + sdkVersion - memset(&encryptInfo,0,dataSize); + // No crypted save, so fill with 0 + tmpData = new u8[128]; + memset(tmpData, 0, 128); + sfoFile.SetValue("SAVEDATA_PARAMS", tmpData, 128, 128); + delete[] tmpData; - encryptInfo.fileVersion = 1; - encryptInfo.sdkVersion = sceKernelGetCompiledSdkVersion(); - if(param->size > 1500) - memcpy(encryptInfo.key,param->key,16); + u8 *sfoData; + size_t sfoSize; + sfoFile.WriteSFO(&sfoData,&sfoSize); + WritePSPFile(sfopath, sfoData, sfoSize); + delete[] sfoData; - std::string encryptInfoPath = dirPath+"/"+"ENCRYPT_INFO.BIN"; - WritePSPFile(encryptInfoPath, (u8*)&encryptInfo, dataSize); - } + // SAVE ICON0 + if (param->icon0FileData.buf) + { + u8* data_ = (u8*)Memory::GetPointer(param->icon0FileData.buf); + std::string icon0path = dirPath+"/"+icon0Name; + WritePSPFile(icon0path, data_, param->icon0FileData.bufSize); + } + // SAVE ICON1 + if (param->icon1FileData.buf) + { + u8* data_ = (u8*)Memory::GetPointer(param->icon1FileData.buf); + std::string icon1path = dirPath+"/"+icon1Name; + WritePSPFile(icon1path, data_, param->icon1FileData.bufSize); + } + // SAVE PIC1 + if (param->pic1FileData.buf) + { + u8* data_ = (u8*)Memory::GetPointer(param->pic1FileData.buf); + std::string pic1path = dirPath+"/"+pic1Name; + WritePSPFile(pic1path, data_, param->pic1FileData.bufSize); + } + + // Save SND + if (param->snd0FileData.buf) + { + u8* data_ = (u8*)Memory::GetPointer(param->snd0FileData.buf); + std::string snd0path = dirPath+"/"+snd0Name; + WritePSPFile(snd0path, data_, param->snd0FileData.bufSize); + } + + // Save Encryption Data + { + EncryptFileInfo encryptInfo; + int dataSize = sizeof(encryptInfo); // version + key + sdkVersion + memset(&encryptInfo,0,dataSize); + + encryptInfo.fileVersion = 1; + encryptInfo.sdkVersion = sceKernelGetCompiledSdkVersion(); + if(param->size > 1500) + memcpy(encryptInfo.key,param->key,16); + + std::string encryptInfoPath = dirPath+"/"+"ENCRYPT_INFO.BIN"; + WritePSPFile(encryptInfoPath, (u8*)&encryptInfo, dataSize); } return true; } @@ -299,7 +335,7 @@ bool SavedataParam::Load(SceUtilitySavedataParam *param, int saveId) return false; } - u8 *data_ = (u8*)Memory::GetPointer(*((unsigned int*)¶m->dataBuf)); + u8 *data_ = (u8*)Memory::GetPointer(param->dataBuf); std::string dirPath = GetSaveFilePath(param, saveId); if (saveId >= 0 && saveNameListDataCount > 0) // if user selection, use it @@ -317,6 +353,7 @@ bool SavedataParam::Load(SceUtilitySavedataParam *param, int saveId) ERROR_LOG(HLE,"Error reading file %s",filePath.c_str()); return false; } + param->dataSize = param->dataBufSize; return true; } @@ -351,9 +388,6 @@ std::string SavedataParam::GetSpaceText(int size) return std::string(text); } -// From my test, PSP only answer with data for save of size 1500 (sdk < 2) -// Perhaps changed to use mode 22 id SDK >= 2 -// For now we always return results bool SavedataParam::GetSizes(SceUtilitySavedataParam *param) { if (!param) { @@ -449,9 +483,12 @@ bool SavedataParam::GetList(SceUtilitySavedataParam *param) { u32 baseAddr = outputBuffer + (i*72); Memory::Write_U32(0x11FF,baseAddr + 0); // mode - Memory::Write_U64(0,baseAddr + 4); // TODO ctime << this seems to not work, write 0 only on 32bits + Memory::Write_U64(0,baseAddr + 4); // TODO ctime + Memory::Write_U64(0,baseAddr + 12); // TODO unknow Memory::Write_U64(0,baseAddr + 20); // TODO atime + Memory::Write_U64(0,baseAddr + 28); // TODO unknow Memory::Write_U64(0,baseAddr + 36); // TODO mtime + Memory::Write_U64(0,baseAddr + 44); // TODO unknow // folder name without gamename (max 20 u8) std::string outName = validDir[i].name.substr(GetGameName(param).size()); Memory::Memset(baseAddr + 52,0,20); @@ -464,6 +501,65 @@ bool SavedataParam::GetList(SceUtilitySavedataParam *param) return true; } +bool SavedataParam::GetFilesList(SceUtilitySavedataParam *param) +{ + if (!param) + { + return false; + } + + u32 dataAddr = param->fileListAddr; + if(!Memory::IsValidAddress(dataAddr)) + return false; + + // TODO : Need to be checked against more game + + u32 fileInfosAddr = Memory::Read_U32(dataAddr + 24); + + //for Valkyria2, dataAddr+0 and dataAddr+12 has "5" for 5 files + int numFiles = Memory::Read_U32(dataAddr+12); + int foundFiles = 0; + for(int i = 0; i < numFiles; i++) + { + // for each file (80 bytes): + // u32 mode, u32 ??, u64 size, u64 ctime, u64 ??, u64 atime, u64 ???, u64 mtime, u64 ??? + // u8[16] filename (or 13 + padding?) + u32 curFileInfoAddr = fileInfosAddr + i*80; + + char fileName[16]; + strncpy(fileName, Memory::GetCharPointer(curFileInfoAddr + 64),16); + std::string filePath = savePath + GetGameName(param) + GetSaveName(param) + "/" + fileName; + PSPFileInfo info = pspFileSystem.GetFileInfo(filePath); + if(info.exists) + { + Memory::Write_U32(0x21FF, curFileInfoAddr+0); + Memory::Write_U64(info.size, curFileInfoAddr+8); + Memory::Write_U64(0,curFileInfoAddr + 16); // TODO ctime + Memory::Write_U64(0,curFileInfoAddr + 24); // TODO unknow + Memory::Write_U64(0,curFileInfoAddr + 32); // TODO atime + Memory::Write_U64(0,curFileInfoAddr + 40); // TODO unknow + Memory::Write_U64(0,curFileInfoAddr + 48); // TODO mtime + Memory::Write_U64(0,curFileInfoAddr + 56); // TODO unknow + foundFiles++; + } + } + + // TODO : verify if return true if at least 1 file found or only if all found + return foundFiles > 0; +} + +bool SavedataParam::GetSizes22(SceUtilitySavedataParam *param) +{ + if (!param) + { + return false; + } + + // TODO code this + + return false; +} + void SavedataParam::Clear() { if (saveDataList) diff --git a/Core/Dialog/SavedataParam.h b/Core/Dialog/SavedataParam.h index 4a1384a8ac..702dc8b5d4 100644 --- a/Core/Dialog/SavedataParam.h +++ b/Core/Dialog/SavedataParam.h @@ -31,7 +31,12 @@ enum SceUtilitySavedataType SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE = 6, SCE_UTILITY_SAVEDATA_TYPE_DELETE = 7, SCE_UTILITY_SAVEDATA_TYPE_SIZES = 8, - SCE_UTILITY_SAVEDATA_TYPE_LIST = 11 + SCE_UTILITY_SAVEDATA_TYPE_LIST = 11, + SCE_UTILITY_SAVEDATA_TYPE_FILES = 12, + SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE = 13, + SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE = 15, + SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE = 17, + SCE_UTILITY_SAVEDATA_TYPE_SIZES22 = 22 } ; // title, savedataTitle, detail: parts of the unencrypted SFO @@ -81,7 +86,7 @@ struct SceUtilitySavedataParam char unused2[3]; /** pointer to a buffer that will contain data file unencrypted data */ - int dataBuf; // Initially void*, but void* in 64bit system take 8 bytes. + u32 dataBuf; // Initially void*, but void* in 64bit system take 8 bytes. /** size of allocated space to dataBuf */ SceSize dataBufSize; SceSize dataSize; // Size of the actual save data @@ -98,9 +103,9 @@ struct SceUtilitySavedataParam int abortStatus; // Function SCE_UTILITY_SAVEDATA_TYPE_SIZES - int msFree; - int msData; - int utilityData; + u32 msFree; + u32 msData; + u32 utilityData; char key[16]; @@ -108,13 +113,13 @@ struct SceUtilitySavedataParam int multiStatus; // Function 11 LIST - int idListAddr; + u32 idListAddr; // Function 12 FILES - int fileListAddr; + u32 fileListAddr; // Function 22 GETSIZES - int sizeAddr; + u32 sizeAddr; }; @@ -147,6 +152,8 @@ public: bool Load(SceUtilitySavedataParam* param, int saveId = -1); bool GetSizes(SceUtilitySavedataParam* param); bool GetList(SceUtilitySavedataParam* param); + bool GetFilesList(SceUtilitySavedataParam* param); + bool GetSizes22(SceUtilitySavedataParam* param); std::string GetGameName(SceUtilitySavedataParam* param); std::string GetSaveName(SceUtilitySavedataParam* param); From 9b92ff3a1f2227a5cafac52adec52862a09a8b36 Mon Sep 17 00:00:00 2001 From: Xele02 Date: Tue, 1 Jan 2013 01:18:39 +0100 Subject: [PATCH 35/89] Add missing dialog display Add Error Log when an Message Dialog Option is not coded --- Core/Dialog/PSPMsgDialog.cpp | 28 ++++++++++++++++++++++++++++ Core/Dialog/PSPMsgDialog.h | 6 +++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/Core/Dialog/PSPMsgDialog.cpp b/Core/Dialog/PSPMsgDialog.cpp index f7e0dd79e2..f72a246484 100644 --- a/Core/Dialog/PSPMsgDialog.cpp +++ b/Core/Dialog/PSPMsgDialog.cpp @@ -44,6 +44,13 @@ int PSPMsgDialog::Init(unsigned int paramAddr) } Memory::ReadStruct(messageDialogAddr, &messageDialog); + // debug info + int optionsNotCoded = ((messageDialog.options | SCE_UTILITY_MSGDIALOG_DEBUG_OPTION_CODED) ^ SCE_UTILITY_MSGDIALOG_DEBUG_OPTION_CODED); + if(optionsNotCoded) + { + ERROR_LOG(HLE,"PSPMsgDialog options not coded : 0x%08x",optionsNotCoded); + } + yesnoChoice = 1; if (messageDialog.type == 0) // number { @@ -56,6 +63,8 @@ int PSPMsgDialog::Init(unsigned int paramAddr) display = DS_MESSAGE; if(messageDialog.options & SCE_UTILITY_MSGDIALOG_OPTION_YESNO) display = DS_YESNO; + if(messageDialog.options & SCE_UTILITY_MSGDIALOG_OPTION_OK) + display = DS_OK; if(messageDialog.options & SCE_UTILITY_MSGDIALOG_OPTION_DEFAULT_NO) yesnoChoice = 0; } @@ -189,6 +198,25 @@ int PSPMsgDialog::Update() } EndDraw(); break; + case DS_OK: + StartDraw(); + + DisplayMessage(text); + + // TODO : Dialogs should take control over input and not send them to the game while displaying + DisplayEnterBack(); + if (IsButtonPressed(cancelButtonFlag)) + { + status = SCE_UTILITY_STATUS_FINISHED; + messageDialog.buttonPressed = 3; + } + else if (IsButtonPressed(okButtonFlag)) + { + status = SCE_UTILITY_STATUS_FINISHED; + messageDialog.buttonPressed = 1; + } + EndDraw(); + break; default: status = SCE_UTILITY_STATUS_FINISHED; return 0; diff --git a/Core/Dialog/PSPMsgDialog.h b/Core/Dialog/PSPMsgDialog.h index 779a77f4e6..c738f5e8d5 100644 --- a/Core/Dialog/PSPMsgDialog.h +++ b/Core/Dialog/PSPMsgDialog.h @@ -22,8 +22,11 @@ #define SCE_UTILITY_MSGDIALOG_OPTION_ERROR 0 // Do nothing #define SCE_UTILITY_MSGDIALOG_OPTION_TEXT 0x00000001 #define SCE_UTILITY_MSGDIALOG_OPTION_YESNO 0x00000010 +#define SCE_UTILITY_MSGDIALOG_OPTION_OK 0x00000020 #define SCE_UTILITY_MSGDIALOG_OPTION_DEFAULT_NO 0x00000100 +#define SCE_UTILITY_MSGDIALOG_DEBUG_OPTION_CODED 0x00000131 // OR of all options coded to display warning + struct pspMessageDialog { pspUtilityDialogCommon common; @@ -32,7 +35,7 @@ struct pspMessageDialog unsigned int errorNum; char string[512]; unsigned int options; - unsigned int buttonPressed; // 0=?, 1=Yes, 2=No, 3=Back + unsigned int buttonPressed; // 0=?, 1=Yes/OK, 2=No, 3=Back }; @@ -58,6 +61,7 @@ private : DS_MESSAGE, DS_ERROR, DS_YESNO, + DS_OK }; DisplayState display; From 8cb87924b3fc399de084d1d91e5fe4fd96185887 Mon Sep 17 00:00:00 2001 From: raven02 Date: Mon, 31 Dec 2012 20:43:38 +0800 Subject: [PATCH 36/89] Add sceKernelSetCompiledSdkVersion401_402 (suggested by Xele02) and wrapped two unload moudles --- Core/HLE/sceKernelMemory.cpp | 21 +++++++++++++++++---- Core/HLE/sceUtility.cpp | 36 ++++++++++++++++++++++++------------ 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index 859c62c43e..5e5ff6aa3e 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -599,10 +599,6 @@ void sceKernelSetCompiledSdkVersion500_505(int sdkVersion) { int sdkMainVersion = sdkVersion & 0xFFFF0000; if(sdkMainVersion == 0x5000000 - || sdkMainVersion == 0x5010000 - || sdkMainVersion == 0x5020000 - || sdkMainVersion == 0x5030000 - || sdkMainVersion == 0x5040000 || sdkMainVersion == 0x5050000) { sdkVersion_ = sdkVersion; @@ -615,6 +611,22 @@ void sceKernelSetCompiledSdkVersion500_505(int sdkVersion) return; } +void sceKernelSetCompiledSdkVersion401_402(int sdkVersion) +{ + int sdkMainVersion = sdkVersion & 0xFFFF0000; + if(sdkMainVersion == 0x4010000 + || sdkMainVersion == 0x4020000) + { + sdkVersion_ = sdkVersion; + flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION; + } + else + { + ERROR_LOG(HLE,"sceKernelSetCompiledSdkVersion401_402 unknown SDK : %x\n",sdkVersion); + } + return; +} + void sceKernelSetCompiledSdkVersion507(int sdkVersion) { int sdkMainVersion = sdkVersion & 0xFFFF0000; @@ -920,6 +932,7 @@ const HLEFunction SysMemUserForUser[] = { {0x342061E5,&WrapV_I,"sceKernelSetCompiledSdkVersion370"}, {0x315AD3A0,&WrapV_I,"sceKernelSetCompiledSdkVersion380_390"}, {0xEBD5C3E6,&WrapV_I,"sceKernelSetCompiledSdkVersion395"}, + {0x057E7380,&WrapV_I,"sceKernelSetCompiledSdkVersion401_402"}, {0xf77d77cb,&WrapV_I,"sceKernelSetCompilerVersion"}, {0x91de343c,&WrapV_I,"sceKernelSetCompiledSdkVersion500_505"}, {0x7893f79a,&WrapV_I,"sceKernelSetCompiledSdkVersion507"}, diff --git a/Core/HLE/sceUtility.cpp b/Core/HLE/sceUtility.cpp index c5dbc84934..bb727f9989 100644 --- a/Core/HLE/sceUtility.cpp +++ b/Core/HLE/sceUtility.cpp @@ -88,20 +88,32 @@ int sceUtilitySavedataUpdate(int animSpeed) #define PSP_AV_MODULE_AAC 6 #define PSP_AV_MODULE_G729 7 -//TODO: Shouldn't be void -void sceUtilityLoadAvModule(u32 module) +u32 sceUtilityLoadAvModule(u32 module) { DEBUG_LOG(HLE,"sceUtilityLoadAvModule(%i)", module); - RETURN(0); - __KernelReSchedule("utilityloadavmodule"); + hleReSchedule("utilityloadavmodule"); + return 0; } -//TODO: Shouldn't be void -void sceUtilityLoadModule(u32 module) +u32 sceUtilityUnloadAvModule(u32 module) +{ + DEBUG_LOG(HLE,"sceUtilityUnloadAvModule(%i)", module); + hleReSchedule("utilityunloadavmodule"); + return 0; +} + +u32 sceUtilityLoadModule(u32 module) { DEBUG_LOG(HLE,"sceUtilityLoadModule(%i)", module); - RETURN(0); - __KernelReSchedule("utilityloadmodule"); + hleReSchedule("utilityloadmodule"); + return 0; +} + +u32 sceUtilityUnloadModule(u32 module) +{ + DEBUG_LOG(HLE,"sceUtilityUnloadModule(%i)", module); + hleReSchedule("utilityunloadmodule"); + return 0; } int sceUtilityMsgDialogInitStart(u32 structAddr) @@ -406,11 +418,11 @@ const HLEFunction sceUtility[] = {0xf5ce1134, 0, "sceUtilityHtmlViewerShutdownStart"}, {0x05afb9e4, 0, "sceUtilityHtmlViewerUpdate"}, - {0xc629af26, &WrapV_U, "sceUtilityLoadAvModule"}, - {0xf7d8d092, 0, "sceUtilityUnloadAvModule"}, + {0xc629af26, &WrapU_U, "sceUtilityLoadAvModule"}, + {0xf7d8d092, &WrapU_U, "sceUtilityUnloadAvModule"}, - {0x2a2b3de0, &WrapV_U, "sceUtilityLoadModule"}, - {0xe49bfe92, 0, "sceUtilityUnloadModule"}, + {0x2a2b3de0, &WrapU_U, "sceUtilityLoadModule"}, + {0xe49bfe92, &WrapU_U, "sceUtilityUnloadModule"}, {0x0251B134, 0, "sceUtilityScreenshotInitStart"}, {0xF9E0008C, 0, "sceUtilityScreenshotShutdownStart"}, From 753e9b3b1682c1dcee9a4f7d9a934cfde5164cd0 Mon Sep 17 00:00:00 2001 From: raven02 Date: Tue, 1 Jan 2013 13:44:40 +0800 Subject: [PATCH 37/89] Fix SW lighting --- GPU/GLES/TransformPipeline.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GLES/TransformPipeline.cpp b/GPU/GLES/TransformPipeline.cpp index 03c3c1901f..b05f0aa690 100644 --- a/GPU/GLES/TransformPipeline.cpp +++ b/GPU/GLES/TransformPipeline.cpp @@ -227,7 +227,7 @@ void Lighter::Light(float colorOut0[4], float colorOut1[4], const float colorIn[ dots[l] = dot; if (gstate.lightEnable[l] & 1) { - Color4 lightAmbient(gstate_c.lightColor[2][l], 1.0f); + Color4 lightAmbient(gstate_c.lightColor[0][l], 1.0f); lightSum0 += lightAmbient * *ambient + diff; } } From daa31bb02d9b8363923ebc8ede0a24749a9bee8a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 31 Dec 2012 21:46:41 -0800 Subject: [PATCH 38/89] Fix fake sceFontGetCharGlyphImage() overflowing. --- Core/HLE/sceFont.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/HLE/sceFont.cpp b/Core/HLE/sceFont.cpp index 8c026e1913..13a3a08ab6 100644 --- a/Core/HLE/sceFont.cpp +++ b/Core/HLE/sceFont.cpp @@ -316,7 +316,7 @@ int sceFontGetCharGlyphImage(u32 libHandler, u32 charCode, u32 glyphImagePtr) int bytesPerLine = Memory::Read_U16(glyphImagePtr+16); int buffer =Memory::Read_U32(glyphImagePtr+20); - Memory::Memset(buffer, 0x7F, bytesPerLine*bufHeight*pixelFormat); + Memory::Memset(buffer, 0x7F, bytesPerLine * bufHeight); return 0; } From 305c41c932d399e1897c3743243f27aa4bdf260e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 31 Dec 2012 23:23:52 -0800 Subject: [PATCH 39/89] Prevent duplicate waiting threads in sema/mutex. If something did a tight loop of a short wait/timeout, it might end up getting on the waitingThreads list multiple times. Eventually this caused a massive performance problem. --- Core/HLE/sceKernelMutex.cpp | 20 ++++++++++++++++---- Core/HLE/sceKernelSemaphore.cpp | 6 +++++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index a591e4ce6d..4469dc0601 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -456,7 +456,10 @@ int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr) return error; else { - mutex->waitingThreads.push_back(__KernelGetCurThread()); + SceUID threadID = __KernelGetCurThread(); + // May be in a tight loop timing out (where we don't remove from waitingThreads yet), don't want to add duplicates. + if (std::find(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID) == mutex->waitingThreads.end()) + mutex->waitingThreads.push_back(threadID); __KernelWaitMutex(mutex, timeoutPtr); __KernelWaitCurThread(WAITTYPE_MUTEX, id, count, timeoutPtr, false); @@ -481,7 +484,10 @@ int sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr) return error; else { - mutex->waitingThreads.push_back(__KernelGetCurThread()); + SceUID threadID = __KernelGetCurThread(); + // May be in a tight loop timing out (where we don't remove from waitingThreads yet), don't want to add duplicates. + if (std::find(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID) == mutex->waitingThreads.end()) + mutex->waitingThreads.push_back(threadID); __KernelWaitMutex(mutex, timeoutPtr); __KernelWaitCurThread(WAITTYPE_MUTEX, id, count, timeoutPtr, true); @@ -813,7 +819,10 @@ int sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr) LwMutex *mutex = kernelObjects.Get(workarea.uid, error); if (mutex) { - mutex->waitingThreads.push_back(__KernelGetCurThread()); + SceUID threadID = __KernelGetCurThread(); + // May be in a tight loop timing out (where we don't remove from waitingThreads yet), don't want to add duplicates. + if (std::find(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID) == mutex->waitingThreads.end()) + mutex->waitingThreads.push_back(threadID); __KernelWaitLwMutex(mutex, timeoutPtr); __KernelWaitCurThread(WAITTYPE_LWMUTEX, workarea.uid, count, timeoutPtr, false); @@ -846,7 +855,10 @@ int sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr) LwMutex *mutex = kernelObjects.Get(workarea.uid, error); if (mutex) { - mutex->waitingThreads.push_back(__KernelGetCurThread()); + SceUID threadID = __KernelGetCurThread(); + // May be in a tight loop timing out (where we don't remove from waitingThreads yet), don't want to add duplicates. + if (std::find(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID) == mutex->waitingThreads.end()) + mutex->waitingThreads.push_back(threadID); __KernelWaitLwMutex(mutex, timeoutPtr); __KernelWaitCurThread(WAITTYPE_LWMUTEX, workarea.uid, count, timeoutPtr, true); diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index f9e5cd4e0b..8fbeb4e674 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -360,7 +360,11 @@ int __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, const char *bad else { s->ns.numWaitThreads++; - s->waitingThreads.push_back(__KernelGetCurThread()); + + SceUID threadID = __KernelGetCurThread(); + // May be in a tight loop timing out (where we don't remove from waitingThreads yet), don't want to add duplicates. + if (std::find(s->waitingThreads.begin(), s->waitingThreads.end(), threadID) == s->waitingThreads.end()) + s->waitingThreads.push_back(threadID); __KernelSetSemaTimeout(s, timeoutPtr); __KernelWaitCurThread(WAITTYPE_SEMA, id, wantedCount, timeoutPtr, processCallbacks); } From 55f986428d7cc9bb1a53042b0b2d24c4b281c1ee Mon Sep 17 00:00:00 2001 From: raven02 Date: Tue, 1 Jan 2013 22:00:20 +0800 Subject: [PATCH 40/89] Use 2.0 alpha value to match real PSP --- GPU/GLES/FragmentShaderGenerator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GLES/FragmentShaderGenerator.cpp b/GPU/GLES/FragmentShaderGenerator.cpp index 7cd7e2302b..143e3b2cf5 100644 --- a/GPU/GLES/FragmentShaderGenerator.cpp +++ b/GPU/GLES/FragmentShaderGenerator.cpp @@ -156,7 +156,7 @@ char *GenerateFragmentShader() } // Color doubling if (gstate.texfunc & 0x10000) { - WRITE(p, " v = v * vec4(2.0, 2.0, 2.0, 1.0);"); + WRITE(p, " v = v * vec4(2.0, 2.0, 2.0, 2.0);"); } if (gstate.alphaTestEnable & 1) { From 39d3b767d9f0ae8dc96fadbed8a4bcde4b705266 Mon Sep 17 00:00:00 2001 From: raven02 Date: Tue, 1 Jan 2013 23:12:45 +0800 Subject: [PATCH 41/89] Fix ambient color in SW Transform --- GPU/GLES/TransformPipeline.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/GPU/GLES/TransformPipeline.cpp b/GPU/GLES/TransformPipeline.cpp index b05f0aa690..82d548c4f8 100644 --- a/GPU/GLES/TransformPipeline.cpp +++ b/GPU/GLES/TransformPipeline.cpp @@ -372,9 +372,9 @@ void TransformDrawEngine::SoftwareTransformAndDraw( c1[j] = 0.0f; } } else { - c0[0] = (gstate.materialambient & 0xFF) / 255.f; - c0[1] = ((gstate.materialambient >> 8) & 0xFF) / 255.f; - c0[2] = ((gstate.materialambient >> 16) & 0xFF) / 255.f; + c0[0] = ((gstate.materialambient >> 16) & 0xFF) / 255.f; + c0[1] = ((gstate.materialambient >> 8) & 0xFF) / 255.f; + c0[2] = (gstate.materialambient & 0xFF) / 255.f; c0[3] = (gstate.materialalpha & 0xFF) / 255.f; } @@ -431,9 +431,9 @@ void TransformDrawEngine::SoftwareTransformAndDraw( if (reader.hasColor0()) { reader.ReadColor0(unlitColor); } else { - unlitColor[0] = (gstate.materialambient & 0xFF) / 255.f; - unlitColor[1] = ((gstate.materialambient >> 8) & 0xFF) / 255.f; - unlitColor[2] = ((gstate.materialambient >> 16) & 0xFF) / 255.f; + unlitColor[0] = ((gstate.materialambient >> 16) & 0xFF) / 255.f; + unlitColor[1] = ((gstate.materialambient >> 8) & 0xFF) / 255.f; + unlitColor[2] = (gstate.materialambient & 0xFF) / 255.f; unlitColor[3] = (gstate.materialalpha & 0xFF) / 255.f; } float litColor0[4]; @@ -462,9 +462,9 @@ void TransformDrawEngine::SoftwareTransformAndDraw( c1[j] = 0.0f; } } else { - c0[0] = (gstate.materialambient & 0xFF) / 255.f; - c0[1] = ((gstate.materialambient >> 8) & 0xFF) / 255.f; - c0[2] = ((gstate.materialambient >> 16) & 0xFF) / 255.f; + c0[0] = ((gstate.materialambient >> 16) & 0xFF) / 255.f; + c0[1] = ((gstate.materialambient >> 8) & 0xFF) / 255.f; + c0[2] = (gstate.materialambient & 0xFF) / 255.f; c0[3] = (gstate.materialalpha & 0xFF) / 255.f; } } From f36a4b3a126d1fe2b83e998bbb26a5ad809180cd Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 1 Jan 2013 19:46:53 -0800 Subject: [PATCH 42/89] Fix a crash when SAVEDATA_FILE_LIST is invalid. I think that's what caused this anyway. --- Core/Dialog/SavedataParam.cpp | 12 ++++++++---- Core/ELF/ParamSFO.h | 19 +++++++++++-------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index 315f13ba82..66ea8c5abc 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -244,18 +244,20 @@ bool SavedataParam::Save(SceUtilitySavedataParam* param, int saveId) sfoFile.SetValue("SAVEDATA_DIRECTORY",GetSaveDir(param,saveId),64); // For each file, 13 bytes for filename, 16 bytes for file hash (0 in PPSSPP), 3 byte for padding - u8* tmpData = sfoFile.GetValueData("SAVEDATA_FILE_LIST", 0); + u32 tmpDataSize = 0; + u8* tmpData = sfoFile.GetValueData("SAVEDATA_FILE_LIST", &tmpDataSize); u8* tmpData2 = 0; if(tmpData == 0) { tmpData2 = new u8[3168]; // 99 filename max tmpData = tmpData2; + tmpDataSize = 3168; memset(tmpData, 0, 3168); } if(param->dataBuf != 0) { - char* fName = (char*)tmpData; - for(int i = 0; i < 99; i++) + char *fName = (char*)tmpData; + for(int i = 0; i < 99 && fName < (char*)tmpData + tmpDataSize; i++) { if(fName[0] == 0) break; // End of list @@ -264,7 +266,9 @@ bool SavedataParam::Save(SceUtilitySavedataParam* param, int saveId) fName += 32; } - snprintf(fName, 20,"%s",GetFileName(param).c_str()); + + if (fName + 20 <= (char*)tmpData + tmpDataSize) + snprintf(fName, 20, "%s",GetFileName(param).c_str()); } sfoFile.SetValue("SAVEDATA_FILE_LIST", tmpData, 3168, 3168); if(tmpData2) diff --git a/Core/ELF/ParamSFO.h b/Core/ELF/ParamSFO.h index fc4e07efc7..438c535560 100644 --- a/Core/ELF/ParamSFO.h +++ b/Core/ELF/ParamSFO.h @@ -54,15 +54,18 @@ private: void SetData(const u8* data, int size) { - if(u_value) + if (data != u_value) { - delete[] u_value; - u_value = 0; - } - if(size > 0) - { - u_value = new u8[size]; - memcpy(u_value,data,size); + if(u_value) + { + delete[] u_value; + u_value = 0; + } + if(size > 0) + { + u_value = new u8[size]; + memcpy(u_value, data, size); + } } u_size = size; } From 62b8b9af758b371ec97a8f3c31b9c9b6f65ad87d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 1 Jan 2013 21:27:18 -0800 Subject: [PATCH 43/89] Fix sceKernelLibcTime() when time_t is 64 bit. --- Core/HLE/HLETables.cpp | 2 +- Core/HLE/sceKernelTime.cpp | 17 ++++++++++------- Core/HLE/sceKernelTime.h | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp index 7a8aba3661..a957fed180 100644 --- a/Core/HLE/HLETables.cpp +++ b/Core/HLE/HLETables.cpp @@ -75,7 +75,7 @@ const HLEFunction FakeSysCalls[] = const HLEFunction UtilsForUser[] = { {0x91E4F6A7, WrapU_V, "sceKernelLibcClock"}, - {0x27CC57F0, sceKernelLibcTime, "sceKernelLibcTime"}, + {0x27CC57F0, WrapU_U, "sceKernelLibcTime"}, {0x71EC4271, sceKernelLibcGettimeofday, "sceKernelLibcGettimeofday"}, {0xBFA98062, WrapV_UI, "sceKernelDcacheInvalidateRange"}, {0xC8186A58, 0, "sceKernelUtilsMd5Digest"}, diff --git a/Core/HLE/sceKernelTime.cpp b/Core/HLE/sceKernelTime.cpp index e7c6be0c4a..4ac9d0007a 100644 --- a/Core/HLE/sceKernelTime.cpp +++ b/Core/HLE/sceKernelTime.cpp @@ -112,14 +112,17 @@ u32 sceKernelLibcClock() return retVal; } -void sceKernelLibcTime() +u32 sceKernelLibcTime(u32 outPtr) { - time_t *t = 0; - if (PARAM(0)) - t = (time_t*)Memory::GetPointer(PARAM(0)); - u32 retVal = (u32)time(t); - DEBUG_LOG(HLE,"%i = sceKernelLibcTime()",retVal); - RETURN(retVal); + time_t t; + time(&t); + + DEBUG_LOG(HLE, "%i = sceKernelLibcTime(%08X)", (u32) t, outPtr); + + if (Memory::IsValidAddress(outPtr)) + Memory::Write_U32((u32) t, outPtr); + + return (u32) t; } void sceKernelLibcGettimeofday() diff --git a/Core/HLE/sceKernelTime.h b/Core/HLE/sceKernelTime.h index bf53e76b5f..f615782c2f 100644 --- a/Core/HLE/sceKernelTime.h +++ b/Core/HLE/sceKernelTime.h @@ -18,7 +18,7 @@ #pragma once void sceKernelLibcGettimeofday(); -void sceKernelLibcTime(); +u32 sceKernelLibcTime(u32 outPtr); void sceKernelUSec2SysClock(); void sceKernelGetSystemTime(); void sceKernelGetSystemTimeLow(); From 4a713309a308d3538306bf006a658f73bcc79950 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 2 Jan 2013 00:35:31 -0800 Subject: [PATCH 44/89] Make some libc-like funcs behave more like hw. --- Core/HLE/sceKernelInterrupt.cpp | 27 ++++++++++++++++++++------- Core/HLE/sceKernelTime.cpp | 6 ++++-- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/Core/HLE/sceKernelInterrupt.cpp b/Core/HLE/sceKernelInterrupt.cpp index 77e7e707a9..ddec34669c 100644 --- a/Core/HLE/sceKernelInterrupt.cpp +++ b/Core/HLE/sceKernelInterrupt.cpp @@ -547,24 +547,37 @@ void QueryIntrHandlerInfo() RETURN(0); } -// TODO: speedup u32 sceKernelMemset(u32 addr, u32 fillc, u32 n) { u8 c = fillc & 0xff; DEBUG_LOG(HLE, "sceKernelMemset(ptr = %08x, c = %02x, n = %08x)", addr, c, n); - for (size_t i = 0; i < n; i++) - Memory::Write_U8((u8)c, addr + i); - return 0; // TODO: verify it should return this + Memory::Memset(addr, c, n); + return addr; } u32 sceKernelMemcpy(u32 dst, u32 src, u32 size) { DEBUG_LOG(HLE, "sceKernelMemcpy(dest=%08x, src=%08x, size=%i)", dst, src, size); - if (Memory::IsValidAddress(dst) && Memory::IsValidAddress(src+size)) // a bit of bound checking. Wrong?? + // Technically should crash if these are invalid and size > 0... + if (Memory::IsValidAddress(dst) && Memory::IsValidAddress(src + size - 1)) { - Memory::Memcpy(dst, Memory::GetPointer(src), size); + u8 *dstp = Memory::GetPointer(dst); + u8 *srcp = Memory::GetPointer(src); + u32 size64 = size / 8; + u32 size8 = size % 8; + + // Try to handle overlapped copies with similar properties to hardware, just in case. + // Not that anyone ought to rely on it. + while (size64-- > 0) + { + *(u64 *) dstp = *(u64 *) srcp; + srcp += 8; + dstp += 8; + } + while (size8-- > 0) + *dstp++ = *srcp++; } - return 0; + return dst; } const HLEFunction Kernel_Library[] = diff --git a/Core/HLE/sceKernelTime.cpp b/Core/HLE/sceKernelTime.cpp index 4ac9d0007a..54b8873f97 100644 --- a/Core/HLE/sceKernelTime.cpp +++ b/Core/HLE/sceKernelTime.cpp @@ -107,8 +107,8 @@ u32 sceKernelUSec2SysClockWide(u32 usec) u32 sceKernelLibcClock() { - u32 retVal = clock()*1000; // TODO: This can't be right - DEBUG_LOG(HLE,"%i = sceKernelLibcClock",retVal); + u32 retVal = (u32) (CoreTiming::GetTicks() / CoreTiming::GetClockFrequencyMHz()); + DEBUG_LOG(HLE, "%i = sceKernelLibcClock", retVal); return retVal; } @@ -121,6 +121,8 @@ u32 sceKernelLibcTime(u32 outPtr) if (Memory::IsValidAddress(outPtr)) Memory::Write_U32((u32) t, outPtr); + else if (outPtr != 0) + return 0; return (u32) t; } From 5bd059a128bc9950dd757b1a9e3336b983ee8a41 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 2 Jan 2013 00:54:23 -0800 Subject: [PATCH 45/89] Do more cache invalidation, fix return values. --- Core/HLE/HLETables.cpp | 10 +++++----- Core/HLE/sceKernel.cpp | 31 +++++++++++++++++++------------ Core/HLE/sceKernel.h | 10 +++++----- 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp index 7a8aba3661..f90600f259 100644 --- a/Core/HLE/HLETables.cpp +++ b/Core/HLE/HLETables.cpp @@ -77,7 +77,7 @@ const HLEFunction UtilsForUser[] = {0x91E4F6A7, WrapU_V, "sceKernelLibcClock"}, {0x27CC57F0, sceKernelLibcTime, "sceKernelLibcTime"}, {0x71EC4271, sceKernelLibcGettimeofday, "sceKernelLibcGettimeofday"}, - {0xBFA98062, WrapV_UI, "sceKernelDcacheInvalidateRange"}, + {0xBFA98062, WrapI_UI, "sceKernelDcacheInvalidateRange"}, {0xC8186A58, 0, "sceKernelUtilsMd5Digest"}, {0x9E5C5086, 0, "sceKernelUtilsMd5BlockInit"}, {0x61E1E525, 0, "sceKernelUtilsMd5BlockUpdate"}, @@ -90,10 +90,10 @@ const HLEFunction UtilsForUser[] = {0x06FB8A63, 0, "sceKernelUtilsMt19937UInt"}, {0x37FB5C42, sceKernelGetGPI, "sceKernelGetGPI"}, {0x6AD345D7, sceKernelSetGPO, "sceKernelSetGPO"}, - {0x79D1C3FA, sceKernelDcacheWritebackAll, "sceKernelDcacheWritebackAll"}, - {0xB435DEC5, sceKernelDcacheWritebackInvalidateAll, "sceKernelDcacheWritebackInvalidateAll"}, - {0x3EE30821, WrapV_UI, "sceKernelDcacheWritebackRange"}, - {0x34B9FA9E, WrapV_UI, "sceKernelDcacheWritebackInvalidateRange"}, + {0x79D1C3FA, WrapI_V, "sceKernelDcacheWritebackAll"}, + {0xB435DEC5, WrapI_V, "sceKernelDcacheWritebackInvalidateAll"}, + {0x3EE30821, WrapI_UI, "sceKernelDcacheWritebackRange"}, + {0x34B9FA9E, WrapI_UI, "sceKernelDcacheWritebackInvalidateRange"}, {0xC2DF770E, 0, "sceKernelIcacheInvalidateRange"}, {0x80001C4C, 0, "sceKernelDcacheProbe"}, {0x16641D70, 0, "sceKernelDcacheReadTag"}, diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index ad62a01ae7..be379dc6b6 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -237,23 +237,30 @@ void sceKernelGetGPI() // Don't even log these, they're spammy and we probably won't // need to emulate them. Might be useful for invalidating cached // textures, and in the future display lists, in some cases though. -void sceKernelDcacheInvalidateRange(u32 addr, int size) +int sceKernelDcacheInvalidateRange(u32 addr, int size) { gpu->InvalidateCache(addr, size); + return 0; } -void sceKernelDcacheWritebackAll() -{ -} -void sceKernelDcacheWritebackRange(u32 addr, int size) -{ -} -void sceKernelDcacheWritebackInvalidateRange(u32 addr, int size) -{ - gpu->InvalidateCache(addr, size); -} -void sceKernelDcacheWritebackInvalidateAll() +int sceKernelDcacheWritebackAll() { gpu->InvalidateCache(0, -1); + return 0; +} +int sceKernelDcacheWritebackRange(u32 addr, int size) +{ + gpu->InvalidateCache(addr, size); + return 0; +} +int sceKernelDcacheWritebackInvalidateRange(u32 addr, int size) +{ + gpu->InvalidateCache(addr, size); + return 0; +} +int sceKernelDcacheWritebackInvalidateAll() +{ + gpu->InvalidateCache(0, -1); + return 0; } KernelObjectPool::KernelObjectPool() diff --git a/Core/HLE/sceKernel.h b/Core/HLE/sceKernel.h index 08c373dfe6..e958bc92fd 100644 --- a/Core/HLE/sceKernel.h +++ b/Core/HLE/sceKernel.h @@ -294,11 +294,11 @@ void sceKernelFindModuleByName(); void sceKernelSetGPO(); void sceKernelGetGPI(); -void sceKernelDcacheInvalidateRange(u32 addr, int size); -void sceKernelDcacheWritebackAll(); -void sceKernelDcacheWritebackRange(u32 addr, int size); -void sceKernelDcacheWritebackInvalidateRange(u32 addr, int size); -void sceKernelDcacheWritebackInvalidateAll(); +int sceKernelDcacheInvalidateRange(u32 addr, int size); +int sceKernelDcacheWritebackAll(); +int sceKernelDcacheWritebackRange(u32 addr, int size); +int sceKernelDcacheWritebackInvalidateRange(u32 addr, int size); +int sceKernelDcacheWritebackInvalidateAll(); void sceKernelGetThreadStackFreeSize(); void sceKernelIcacheInvalidateAll(); void sceKernelIcacheClearAll(); From 1c156784b65d0a4bc6cfee33767b9fc851b2ba69 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 2 Jan 2013 01:09:44 -0800 Subject: [PATCH 46/89] Be more deterministic about the time. This way, if a state is loaded, the game doesn't know. Also, if the host is slow/sped up, it won't get out of sync. --- Core/HLE/sceKernel.cpp | 2 ++ Core/HLE/sceKernelTime.cpp | 27 ++++++++++++++++++++++----- Core/HLE/sceKernelTime.h | 3 +++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index ad62a01ae7..5ec6313275 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -79,6 +79,7 @@ void __KernelInit() } SaveState::Init(); + __KernelTimeInit(); __InterruptsInit(); __KernelMemoryInit(); __KernelThreadingInit(); @@ -154,6 +155,7 @@ void __KernelDoState(PointerWrap &p) __KernelModuleDoState(p); __KernelMutexDoState(p); __KernelSemaDoState(p); + __KernelTimeDoState(p); __AudioDoState(p); __CtrlDoState(p); diff --git a/Core/HLE/sceKernelTime.cpp b/Core/HLE/sceKernelTime.cpp index 54b8873f97..e5cb09a9f5 100644 --- a/Core/HLE/sceKernelTime.cpp +++ b/Core/HLE/sceKernelTime.cpp @@ -30,10 +30,28 @@ #include "../CoreTiming.h" +////////////////////////////////////////////////////////////////////////// +// State +////////////////////////////////////////////////////////////////////////// + +// The time when the game started. +time_t start_time; + ////////////////////////////////////////////////////////////////////////// // Other clock stuff ////////////////////////////////////////////////////////////////////////// +void __KernelTimeInit() +{ + time(&start_time); +} + +void __KernelTimeDoState(PointerWrap &p) +{ + p.Do(start_time); + p.DoMarker("sceKernelTime"); +} + struct SceKernelSysClock { u32 lo; @@ -114,17 +132,16 @@ u32 sceKernelLibcClock() u32 sceKernelLibcTime(u32 outPtr) { - time_t t; - time(&t); + u32 t = (u32) start_time + (u32) (CoreTiming::GetTicks() / CPU_HZ); - DEBUG_LOG(HLE, "%i = sceKernelLibcTime(%08X)", (u32) t, outPtr); + DEBUG_LOG(HLE, "%i = sceKernelLibcTime(%08X)", t, outPtr); if (Memory::IsValidAddress(outPtr)) - Memory::Write_U32((u32) t, outPtr); + Memory::Write_U32(t, outPtr); else if (outPtr != 0) return 0; - return (u32) t; + return t; } void sceKernelLibcGettimeofday() diff --git a/Core/HLE/sceKernelTime.h b/Core/HLE/sceKernelTime.h index f615782c2f..4ab8e59ec6 100644 --- a/Core/HLE/sceKernelTime.h +++ b/Core/HLE/sceKernelTime.h @@ -27,3 +27,6 @@ void sceKernelSysClock2USec(); void sceKernelSysClock2USecWide(); u32 sceKernelUSec2SysClockWide(u32 usec); u32 sceKernelLibcClock(); + +void __KernelTimeInit(); +void __KernelTimeDoState(PointerWrap &p); From 5d892e005dbdc4d823444f03304e9f696759a2cc Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 2 Jan 2013 01:37:03 -0800 Subject: [PATCH 47/89] Let ParamSFO always own its pointers. --- Core/Dialog/SavedataParam.cpp | 33 +++++++++++++++++---------------- Core/ELF/ParamSFO.h | 19 ++++++++----------- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index 66ea8c5abc..0c34ce9e63 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -244,35 +244,36 @@ bool SavedataParam::Save(SceUtilitySavedataParam* param, int saveId) sfoFile.SetValue("SAVEDATA_DIRECTORY",GetSaveDir(param,saveId),64); // For each file, 13 bytes for filename, 16 bytes for file hash (0 in PPSSPP), 3 byte for padding + const int FILE_LIST_ITEM_SIZE = 13 + 16 + 3; + const int FILE_LIST_COUNT_MAX = 99; + const int FILE_LIST_TOTAL_SIZE = FILE_LIST_ITEM_SIZE * FILE_LIST_COUNT_MAX; u32 tmpDataSize = 0; - u8* tmpData = sfoFile.GetValueData("SAVEDATA_FILE_LIST", &tmpDataSize); - u8* tmpData2 = 0; - if(tmpData == 0) - { - tmpData2 = new u8[3168]; // 99 filename max - tmpData = tmpData2; - tmpDataSize = 3168; - memset(tmpData, 0, 3168); - } - if(param->dataBuf != 0) + u8* tmpDataOrig = sfoFile.GetValueData("SAVEDATA_FILE_LIST", &tmpDataSize); + u8* tmpData = new u8[FILE_LIST_TOTAL_SIZE]; + + if (tmpDataOrig != NULL) + memcpy(tmpData, tmpDataOrig, tmpDataSize > FILE_LIST_TOTAL_SIZE ? FILE_LIST_TOTAL_SIZE : tmpDataSize); + else + memset(tmpData, 0, FILE_LIST_TOTAL_SIZE); + + if (param->dataBuf != 0) { char *fName = (char*)tmpData; - for(int i = 0; i < 99 && fName < (char*)tmpData + tmpDataSize; i++) + for(int i = 0; i < FILE_LIST_COUNT_MAX; i++) { if(fName[0] == 0) break; // End of list if(strncmp(fName,GetFileName(param).c_str(),20) == 0) break; // File already in SFO - fName += 32; + fName += FILE_LIST_ITEM_SIZE; } - if (fName + 20 <= (char*)tmpData + tmpDataSize) + if (fName + 20 <= (char*)tmpData + FILE_LIST_TOTAL_SIZE) snprintf(fName, 20, "%s",GetFileName(param).c_str()); } - sfoFile.SetValue("SAVEDATA_FILE_LIST", tmpData, 3168, 3168); - if(tmpData2) - delete[] tmpData2; + sfoFile.SetValue("SAVEDATA_FILE_LIST", tmpData, FILE_LIST_TOTAL_SIZE, FILE_LIST_TOTAL_SIZE); + delete[] tmpData; // No crypted save, so fill with 0 tmpData = new u8[128]; diff --git a/Core/ELF/ParamSFO.h b/Core/ELF/ParamSFO.h index 438c535560..5f842dfecf 100644 --- a/Core/ELF/ParamSFO.h +++ b/Core/ELF/ParamSFO.h @@ -54,18 +54,15 @@ private: void SetData(const u8* data, int size) { - if (data != u_value) + if(u_value) { - if(u_value) - { - delete[] u_value; - u_value = 0; - } - if(size > 0) - { - u_value = new u8[size]; - memcpy(u_value, data, size); - } + delete[] u_value; + u_value = 0; + } + if(size > 0) + { + u_value = new u8[size]; + memcpy(u_value, data, size); } u_size = size; } From d657fc9fa20fdb303d9927c42250e8990042e40a Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Wed, 2 Jan 2013 13:50:52 +0100 Subject: [PATCH 48/89] Disable clearing all the GPU's cache on sceKernelCacheWritebackAll, the performance penalty was too big. --- Core/HLE/sceKernel.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index c750d09142..94eebea14a 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -246,7 +246,9 @@ int sceKernelDcacheInvalidateRange(u32 addr, int size) } int sceKernelDcacheWritebackAll() { - gpu->InvalidateCache(0, -1); + // Some games seem to use this a lot, it doesn't make sense + // to zap the whole texture cache. + // gpu->InvalidateCache(0, -1); return 0; } int sceKernelDcacheWritebackRange(u32 addr, int size) From 15196004412b5f69d7a512d2855ca9324ea2cb49 Mon Sep 17 00:00:00 2001 From: Arthur Blot Date: Wed, 2 Jan 2013 00:36:34 +0100 Subject: [PATCH 49/89] Implemented sceKernelLoadModuleByID, better logs --- Core/ELF/ElfReader.cpp | 14 +++--- Core/ELF/PrxDecrypter.cpp | 30 +++++++++++++ Core/ELF/PrxDecrypter.h | 2 + Core/HLE/sceIo.cpp | 38 ---------------- Core/HLE/sceIo.h | 39 ++++++++++++++++ Core/HLE/sceKernelModule.cpp | 86 ++++++++++++++++++++++++++---------- 6 files changed, 140 insertions(+), 69 deletions(-) diff --git a/Core/ELF/ElfReader.cpp b/Core/ELF/ElfReader.cpp index 2969b975e5..dd0cf8247a 100644 --- a/Core/ELF/ElfReader.cpp +++ b/Core/ELF/ElfReader.cpp @@ -271,6 +271,7 @@ bool ElfReader::LoadInto(u32 loadAddress) } DEBUG_LOG(LOADER,"Relocations:"); + bool oldRelocs = false; // Second pass: Do necessary relocations for (int i=0; ish_info; - if (!(sections[sectionToModify].sh_flags & SHF_ALLOC)) - { - ERROR_LOG(LOADER,"Trying to relocate non-loaded section %s, ignoring",GetSectionName(sectionToModify)); - continue; - } - ERROR_LOG(LOADER,"Traditional relocations unsupported."); + oldRelocs = true; } } } + if (oldRelocs) + { + INFO_LOG(LOADER, "Game uses old relocations (often for debugging, should be harmless)"); + } // Segment relocations (a few games use them) if (GetNumSections() == 0) diff --git a/Core/ELF/PrxDecrypter.cpp b/Core/ELF/PrxDecrypter.cpp index 8541c0358c..38ddc980f9 100644 --- a/Core/ELF/PrxDecrypter.cpp +++ b/Core/ELF/PrxDecrypter.cpp @@ -6,6 +6,7 @@ extern "C" } #include "../../Globals.h" +#include "PrxDecrypter.h" // Thank you PSARDUMPER & JPCSP keys @@ -287,6 +288,22 @@ static const TAG_INFO g_tagInfo[] = { 0xBB67C59F, g_key_GAMESHARE2xx, 0x5E, 0x5E } }; +bool HasKey(int key) +{ + switch (key) + { + case 0x02: case 0x03: case 0x04: case 0x05: case 0x07: case 0x0C: case 0x0D: case 0x0E: case 0x0F: + case 0x10: case 0x11: case 0x12: + case 0x38: case 0x39: case 0x3A: case 0x44: case 0x4B: + case 0x53: case 0x57: case 0x5D: + case 0x63: case 0x64: + return true; + default: + INFO_LOG(HLE, "Missing key %02X, cannot decrypt module", key); + return false; + } +} + static const TAG_INFO *GetTagInfo(u32 tagFind) { for (u32 iTag = 0; iTag < sizeof(g_tagInfo)/sizeof(TAG_INFO); iTag++) @@ -341,6 +358,11 @@ static int DecryptPRX1(const u8* pbIn, u8* pbOut, int cbTotal, u32 tag) { return -1; } + if (!HasKey(pti->code) || + (pti->codeExtra != 0 && !HasKey(pti->codeExtra))) + { + return MISSING_KEY; + } retsize = *(u32*)&pbIn[0xB0]; @@ -589,6 +611,10 @@ static int DecryptPRX2(const u8 *inbuf, u8 *outbuf, u32 size, u32 tag) { return -1; } + if (!HasKey(pti->code)) + { + return MISSING_KEY; + } int retsize = *(int *)&inbuf[0xB0]; u8 tmp1[0x150], tmp2[0x90+0x14], tmp3[0x90+0x14], tmp4[0x20]; @@ -724,6 +750,10 @@ int pspDecryptPRX(const u8 *inbuf, u8 *outbuf, u32 size) { kirk_init(); int retsize = DecryptPRX1(inbuf, outbuf, size, *(u32 *)&inbuf[0xD0]); + if (retsize == MISSING_KEY) + { + return MISSING_KEY; + } if (retsize <= 0) { diff --git a/Core/ELF/PrxDecrypter.h b/Core/ELF/PrxDecrypter.h index 23cbedbc1a..afb4f2d555 100644 --- a/Core/ELF/PrxDecrypter.h +++ b/Core/ELF/PrxDecrypter.h @@ -19,6 +19,8 @@ #include "../../Globals.h" +#define MISSING_KEY -10 + #ifdef _MSC_VER #pragma pack(push, 1) #endif diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index 4f5ff5c8a4..5daa4d89f1 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -20,7 +20,6 @@ #undef DeleteFile #endif -#include "../System.h" #include "../Config.h" #include "../Host.h" #include "../SaveState.h" @@ -121,43 +120,6 @@ struct dirent { }; #endif -class FileNode : public KernelObject { -public: - FileNode() : callbackID(0), callbackArg(0), asyncResult(0), pendingAsyncResult(false), sectorBlockMode(false) {} - ~FileNode() { - pspFileSystem.CloseFile(handle); - } - const char *GetName() {return fullpath.c_str();} - const char *GetTypeName() {return "OpenFile";} - void GetQuickInfo(char *ptr, int size) { - sprintf(ptr, "Seekpos: %08x", (u32)pspFileSystem.GetSeekPos(handle)); - } - static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_BADF; } - int GetIDType() const { return PPSSPP_KERNEL_TMID_File; } - - virtual void DoState(PointerWrap &p) { - p.Do(fullpath); - p.Do(handle); - p.Do(callbackID); - p.Do(callbackArg); - p.Do(asyncResult); - p.Do(pendingAsyncResult); - p.Do(sectorBlockMode); - p.DoMarker("File"); - } - - std::string fullpath; - u32 handle; - - u32 callbackID; - u32 callbackArg; - - u32 asyncResult; - - bool pendingAsyncResult; - bool sectorBlockMode; -}; - void __IoInit() { INFO_LOG(HLE, "Starting up I/O..."); diff --git a/Core/HLE/sceIo.h b/Core/HLE/sceIo.h index d05c00df06..cd88521401 100644 --- a/Core/HLE/sceIo.h +++ b/Core/HLE/sceIo.h @@ -18,9 +18,48 @@ #pragma once #include + +#include "../System.h" #include "HLE.h" #include "sceKernel.h" +class FileNode : public KernelObject { +public: + FileNode() : callbackID(0), callbackArg(0), asyncResult(0), pendingAsyncResult(false), sectorBlockMode(false) {} + ~FileNode() { + pspFileSystem.CloseFile(handle); + } + const char *GetName() {return fullpath.c_str();} + const char *GetTypeName() {return "OpenFile";} + void GetQuickInfo(char *ptr, int size) { + sprintf(ptr, "Seekpos: %08x", (u32)pspFileSystem.GetSeekPos(handle)); + } + static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_BADF; } + int GetIDType() const { return PPSSPP_KERNEL_TMID_File; } + + virtual void DoState(PointerWrap &p) { + p.Do(fullpath); + p.Do(handle); + p.Do(callbackID); + p.Do(callbackArg); + p.Do(asyncResult); + p.Do(pendingAsyncResult); + p.Do(sectorBlockMode); + p.DoMarker("File"); + } + + std::string fullpath; + u32 handle; + + u32 callbackID; + u32 callbackArg; + + u32 asyncResult; + + bool pendingAsyncResult; + bool sectorBlockMode; +}; + void __IoInit(); void __IoDoState(PointerWrap &p); void __IoShutdown(); diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 8f35526859..dc99ba1f4d 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -39,6 +39,7 @@ #include "sceKernelModule.h" #include "sceKernelThread.h" #include "sceKernelMemory.h" +#include "sceIo.h" enum { PSP_THREAD_ATTR_USER = 0x80000000 @@ -100,7 +101,7 @@ struct NativeModule { class Module : public KernelObject { public: - Module() : memoryBlockAddr(0) {} + Module() : memoryBlockAddr(0), isFake(false) {} ~Module() { if (memoryBlockAddr) { userMemory.Free(memoryBlockAddr); @@ -129,6 +130,7 @@ public: NativeModule nm; u32 memoryBlockAddr; + bool isFake; }; KernelObject *__KernelModuleObject() @@ -212,6 +214,10 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro kernelObjects.Create(module); u8 *newptr = 0; + if (*(u32*)ptr == 0x4543537e) { // "~SCE" + INFO_LOG(HLE, "~SCE module, skipping header"); + ptr += *(u32*)(ptr + 4); + } if (*(u32*)ptr == 0x5053507e) { // "~PSP" // Decrypt module! YAY! @@ -225,20 +231,20 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro } newptr = new u8[head->elf_size + head->psp_size]; ptr = newptr; - pspDecryptPRX(in, (u8*)ptr, head->psp_size); + int ret = pspDecryptPRX(in, (u8*)ptr, head->psp_size); + if (ret == MISSING_KEY) + { + *error_string = "Missing key"; + delete [] newptr; + module->isFake = true; + return module; + } + else if (ret <= 0) + { + ERROR_LOG(HLE, "Failed decrypting PRX! That's not normal!\n"); + } } - if (*(u32*)ptr == 0x4543537e) { // "~SCE" - ERROR_LOG(HLE, "Wrong magic number %08x (~SCE, kernel module?)",*(u32*)ptr); - *error_string = "Kernel module?"; - if (newptr) - { - delete [] newptr; - } - kernelObjects.Destroy(module->GetUID()); - return 0; - } - if (*(u32*)ptr != 0x464c457f) { ERROR_LOG(HLE, "Wrong magic number %08x",*(u32*)ptr); @@ -688,9 +694,6 @@ u32 sceKernelLoadModule(const char *name, u32 flags) void sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 returnValueAddr, u32 optionAddr) { - ERROR_LOG(HLE,"UNIMPL sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x)", - moduleId,argsize,argAddr,returnValueAddr,optionAddr); - // Dunno what these three defaults should be... u32 priority = 0x20; u32 stacksize = 0x40000; @@ -707,12 +710,15 @@ void sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 returnValu u32 error; Module *module = kernelObjects.Get(moduleId, error); if (!module) { - // TODO: Try not to lie so much. - /* RETURN(error); return; - */ + } else if (module->isFake) { + INFO_LOG(HLE,"sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x): faked (undecryptable module)", + moduleId,argsize,argAddr,returnValueAddr,optionAddr); } else { + ERROR_LOG(HLE,"UNIMPL sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x)", + moduleId,argsize,argAddr,returnValueAddr,optionAddr); + u32 entryAddr = module->nm.entry_addr; if (entryAddr == -1) { entryAddr = module->nm.module_start_func; @@ -785,10 +791,44 @@ void sceKernelFindModuleByName() RETURN(1); } -u32 sceKernelLoadModuleByID(u32 id, u32 flags, u32 lmoptionPtr) { - ERROR_LOG(HLE,"UNIMPL %008x=sceKernelLoadModuleById(%08x, %08x)",id,id,lmoptionPtr); - // Apparenty, ID is a sceIo File UID. So this shouldn't be too hard when needed. - return id; +u32 sceKernelLoadModuleByID(u32 id, u32 flags, u32 lmoptionPtr) +{ + u32 error; + FileNode *f = kernelObjects.Get < FileNode > (id, error); + if (!f) { + ERROR_LOG(HLE,"sceKernelLoadModuleByID(%08x, %08x, %08x): could not open file id",id,flags,lmoptionPtr); + return error; + } + SceKernelLMOption *lmoption = 0; + if (lmoptionPtr) { + lmoption = (SceKernelLMOption *)Memory::GetPointer(lmoptionPtr); + } + u32 pos = pspFileSystem.SeekFile(f->handle, 0, FILEMOVE_CURRENT); + u32 size = pspFileSystem.SeekFile(f->handle, 0, FILEMOVE_END); + std::string error_string; + pspFileSystem.SeekFile(f->handle, pos, FILEMOVE_BEGIN); + Module *module = 0; + u8 *temp = new u8[size]; + pspFileSystem.ReadFile(f->handle, temp, size); + module = __KernelLoadELFFromPtr(temp, 0, &error_string); + delete [] temp; + + if (!module) { + // Module was blacklisted or couldn't be decrypted, which means it's a kernel module we don't want to run. + // Let's just act as if it worked. + NOTICE_LOG(LOADER, "Module %d is blacklisted or undecryptable - we lie about success", id); + return 1; + } + + if (lmoption) { + INFO_LOG(HLE,"%i=sceKernelLoadModuleByID(%d,flag=%08x,%08x,%08x,%08x,position = %08x)", + module->GetUID(),id,flags, + lmoption->size,lmoption->mpidtext,lmoption->mpiddata,lmoption->position); + } else { + INFO_LOG(HLE,"%i=sceKernelLoadModuleByID(%d,flag=%08x,(...))", module->GetUID(), id, flags); + } + + return module->GetUID(); } u32 sceKernelLoadModuleDNAS(const char *name, u32 flags) From 73de0e9494f1d9e37bfe10a60fae2fad2d4f622c Mon Sep 17 00:00:00 2001 From: Arthur Blot Date: Wed, 2 Jan 2013 00:48:30 +0100 Subject: [PATCH 50/89] Consider blacklisted modules as fake --- Core/HLE/sceKernelModule.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index dc99ba1f4d..89b7cd540e 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -313,8 +313,8 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro { delete [] newptr; } - kernelObjects.Destroy(module->GetUID()); - return 0; + module->isFake = true; + return module; } } From c2851467e5671b09ec842e977974c664d6e4334b Mon Sep 17 00:00:00 2001 From: Arthur Blot Date: Wed, 2 Jan 2013 01:08:18 +0100 Subject: [PATCH 51/89] No more useless errors/warnings at all! --- Core/FileSystems/DirectoryFileSystem.cpp | 17 ++++++++++------- Core/FileSystems/ISOFileSystem.cpp | 9 ++++++--- Core/FileSystems/ISOFileSystem.h | 2 +- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp index e742ebe255..cbf7bb9e80 100644 --- a/Core/FileSystems/DirectoryFileSystem.cpp +++ b/Core/FileSystems/DirectoryFileSystem.cpp @@ -490,19 +490,22 @@ PSPFileInfo DirectoryFileSystem::GetFileInfo(std::string filename) { return x; #endif } - x.type = File::IsDirectory(fullName) ? FILETYPE_NORMAL : FILETYPE_DIRECTORY; + x.type = File::IsDirectory(fullName) ? FILETYPE_DIRECTORY : FILETYPE_NORMAL; x.exists = true; + if (x.type != FILETYPE_DIRECTORY) + { #ifdef _WIN32 - WIN32_FILE_ATTRIBUTE_DATA data; - GetFileAttributesEx(fullName.c_str(), GetFileExInfoStandard, &data); + WIN32_FILE_ATTRIBUTE_DATA data; + GetFileAttributesEx(fullName.c_str(), GetFileExInfoStandard, &data); - x.size = data.nFileSizeLow | ((u64)data.nFileSizeHigh<<32); + x.size = data.nFileSizeLow | ((u64)data.nFileSizeHigh<<32); #else - x.size = File::GetSize(fullName); - //TODO + x.size = File::GetSize(fullName); + //TODO #endif - x.mtime = File::GetModifTime(fullName); + x.mtime = File::GetModifTime(fullName); + } return x; } diff --git a/Core/FileSystems/ISOFileSystem.cpp b/Core/FileSystems/ISOFileSystem.cpp index b054b6bf72..c526be4c15 100644 --- a/Core/FileSystems/ISOFileSystem.cpp +++ b/Core/FileSystems/ISOFileSystem.cpp @@ -240,7 +240,7 @@ nextblock: } -ISOFileSystem::TreeEntry *ISOFileSystem::GetFromPath(std::string path) +ISOFileSystem::TreeEntry *ISOFileSystem::GetFromPath(std::string path, bool catchError) { if (path.length() == 0) { @@ -297,7 +297,10 @@ ISOFileSystem::TreeEntry *ISOFileSystem::GetFromPath(std::string path) } else { - ERROR_LOG(FILESYS,"File %s not found", path.c_str()); + if (catchError) + { + ERROR_LOG(FILESYS,"File %s not found", path.c_str()); + } return 0; } } @@ -502,7 +505,7 @@ PSPFileInfo ISOFileSystem::GetFileInfo(std::string filename) return fileInfo; } - TreeEntry *entry = GetFromPath(filename); + TreeEntry *entry = GetFromPath(filename, false); PSPFileInfo x; if (!entry) { diff --git a/Core/FileSystems/ISOFileSystem.h b/Core/FileSystems/ISOFileSystem.h index 96e88e0710..f07b25850d 100644 --- a/Core/FileSystems/ISOFileSystem.h +++ b/Core/FileSystems/ISOFileSystem.h @@ -67,7 +67,7 @@ class ISOFileSystem : public IFileSystem TreeEntry entireISO; void ReadDirectory(u32 startsector, u32 dirsize, TreeEntry *root); - TreeEntry *GetFromPath(std::string path); + TreeEntry *GetFromPath(std::string path, bool catchError=true); std::string EntryFullPath(TreeEntry *e); public: From e4ce0592c1be5ccb7975d65b618ff20596572494 Mon Sep 17 00:00:00 2001 From: Arthur Blot Date: Wed, 2 Jan 2013 12:35:37 +0100 Subject: [PATCH 52/89] Make previous code cleaner --- Core/ELF/ElfReader.cpp | 16 +++++++------ Core/HLE/sceIo.cpp | 46 ++++++++++++++++++++++++++++++++++++ Core/HLE/sceIo.h | 38 +---------------------------- Core/HLE/sceKernelModule.cpp | 12 +++++----- 4 files changed, 62 insertions(+), 50 deletions(-) diff --git a/Core/ELF/ElfReader.cpp b/Core/ELF/ElfReader.cpp index dd0cf8247a..3ead77cf28 100644 --- a/Core/ELF/ElfReader.cpp +++ b/Core/ELF/ElfReader.cpp @@ -271,7 +271,6 @@ bool ElfReader::LoadInto(u32 loadAddress) } DEBUG_LOG(LOADER,"Relocations:"); - bool oldRelocs = false; // Second pass: Do necessary relocations for (int i=0; ish_type == SHT_REL) { DEBUG_LOG(LOADER, "Traditional relocation section found."); - if (bRelocate) + if (!bRelocate) { DEBUG_LOG(LOADER, "Binary is prerelocated. Skipping relocations."); } else { - oldRelocs = true; + //We have a relocation table! + int sectionToModify = s->sh_info; + if (!(sections[sectionToModify].sh_flags & SHF_ALLOC)) + { + ERROR_LOG(LOADER,"Trying to relocate non-loaded section %s, ignoring",GetSectionName(sectionToModify)); + continue; + } + ERROR_LOG(LOADER,"Traditional relocations unsupported."); } } } - if (oldRelocs) - { - INFO_LOG(LOADER, "Game uses old relocations (often for debugging, should be harmless)"); - } // Segment relocations (a few games use them) if (GetNumSections() == 0) diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index 5daa4d89f1..11578688c6 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -120,6 +120,43 @@ struct dirent { }; #endif +class FileNode : public KernelObject { +public: + FileNode() : callbackID(0), callbackArg(0), asyncResult(0), pendingAsyncResult(false), sectorBlockMode(false) {} + ~FileNode() { + pspFileSystem.CloseFile(handle); + } + const char *GetName() {return fullpath.c_str();} + const char *GetTypeName() {return "OpenFile";} + void GetQuickInfo(char *ptr, int size) { + sprintf(ptr, "Seekpos: %08x", (u32)pspFileSystem.GetSeekPos(handle)); + } + static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_BADF; } + int GetIDType() const { return PPSSPP_KERNEL_TMID_File; } + + virtual void DoState(PointerWrap &p) { + p.Do(fullpath); + p.Do(handle); + p.Do(callbackID); + p.Do(callbackArg); + p.Do(asyncResult); + p.Do(pendingAsyncResult); + p.Do(sectorBlockMode); + p.DoMarker("File"); + } + + std::string fullpath; + u32 handle; + + u32 callbackID; + u32 callbackArg; + + u32 asyncResult; + + bool pendingAsyncResult; + bool sectorBlockMode; +}; + void __IoInit() { INFO_LOG(HLE, "Starting up I/O..."); @@ -175,6 +212,15 @@ void __IoShutdown() { defParam = 0; } +u32 __IoGetFileHandleFromId(u32 id, u32 &outError) +{ + FileNode *f = kernelObjects.Get < FileNode > (id, outError); + if (!f) { + return -1; + } + return f->handle; +} + u32 sceIoAssign(const char *aliasname, const char *physname, const char *devname, u32 flag) { ERROR_LOG(HLE, "UNIMPL sceIoAssign(%s, %s, %s, %08x, ...)", aliasname, physname, devname, flag); diff --git a/Core/HLE/sceIo.h b/Core/HLE/sceIo.h index cd88521401..2945a396c1 100644 --- a/Core/HLE/sceIo.h +++ b/Core/HLE/sceIo.h @@ -23,46 +23,10 @@ #include "HLE.h" #include "sceKernel.h" -class FileNode : public KernelObject { -public: - FileNode() : callbackID(0), callbackArg(0), asyncResult(0), pendingAsyncResult(false), sectorBlockMode(false) {} - ~FileNode() { - pspFileSystem.CloseFile(handle); - } - const char *GetName() {return fullpath.c_str();} - const char *GetTypeName() {return "OpenFile";} - void GetQuickInfo(char *ptr, int size) { - sprintf(ptr, "Seekpos: %08x", (u32)pspFileSystem.GetSeekPos(handle)); - } - static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_BADF; } - int GetIDType() const { return PPSSPP_KERNEL_TMID_File; } - - virtual void DoState(PointerWrap &p) { - p.Do(fullpath); - p.Do(handle); - p.Do(callbackID); - p.Do(callbackArg); - p.Do(asyncResult); - p.Do(pendingAsyncResult); - p.Do(sectorBlockMode); - p.DoMarker("File"); - } - - std::string fullpath; - u32 handle; - - u32 callbackID; - u32 callbackArg; - - u32 asyncResult; - - bool pendingAsyncResult; - bool sectorBlockMode; -}; - void __IoInit(); void __IoDoState(PointerWrap &p); void __IoShutdown(); +u32 __IoGetFileHandleFromId(u32 id, u32 &outError); KernelObject *__KernelFileNodeObject(); KernelObject *__KernelDirListingObject(); diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 89b7cd540e..d590dc36e8 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -794,8 +794,8 @@ void sceKernelFindModuleByName() u32 sceKernelLoadModuleByID(u32 id, u32 flags, u32 lmoptionPtr) { u32 error; - FileNode *f = kernelObjects.Get < FileNode > (id, error); - if (!f) { + u32 handle = __IoGetFileHandleFromId(id, error); + if (handle < 0) { ERROR_LOG(HLE,"sceKernelLoadModuleByID(%08x, %08x, %08x): could not open file id",id,flags,lmoptionPtr); return error; } @@ -803,13 +803,13 @@ u32 sceKernelLoadModuleByID(u32 id, u32 flags, u32 lmoptionPtr) if (lmoptionPtr) { lmoption = (SceKernelLMOption *)Memory::GetPointer(lmoptionPtr); } - u32 pos = pspFileSystem.SeekFile(f->handle, 0, FILEMOVE_CURRENT); - u32 size = pspFileSystem.SeekFile(f->handle, 0, FILEMOVE_END); + u32 pos = pspFileSystem.SeekFile(handle, 0, FILEMOVE_CURRENT); + u32 size = pspFileSystem.SeekFile(handle, 0, FILEMOVE_END); std::string error_string; - pspFileSystem.SeekFile(f->handle, pos, FILEMOVE_BEGIN); + pspFileSystem.SeekFile(handle, pos, FILEMOVE_BEGIN); Module *module = 0; u8 *temp = new u8[size]; - pspFileSystem.ReadFile(f->handle, temp, size); + pspFileSystem.ReadFile(handle, temp, size); module = __KernelLoadELFFromPtr(temp, 0, &error_string); delete [] temp; From 41ea4ff358a7bc3daeb81a2f43064e74d493c0dc Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Wed, 2 Jan 2013 20:54:09 +0100 Subject: [PATCH 53/89] Move memstick data on Android to external memory (sdcard/usb storage) --- android/jni/NativeApp.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/android/jni/NativeApp.cpp b/android/jni/NativeApp.cpp index d732413783..cbec8230ac 100644 --- a/android/jni/NativeApp.cpp +++ b/android/jni/NativeApp.cpp @@ -232,7 +232,13 @@ void NativeInit(int argc, const char *argv[], const char *savegame_directory, co #endif } -#if defined(ANDROID) || defined(BLACKBERRY) || defined(__SYMBIAN32__) +#if defined(ANDROID) + // Maybe there should be an option to use internal memory instead, but I think + // that for most people, using external memory (SDCard/USB Storage) makes the + // most sense. + g_Config.memCardDirectory = std::string(external_directory) + "/"; + g_Config.flashDirectory = std::string(external_directory)+"/flash/"; +#elif defined(BLACKBERRY) || defined(__SYMBIAN32__) g_Config.memCardDirectory = user_data_path; g_Config.flashDirectory = user_data_path+"/flash/"; #else From 972e4ea4e4e8a365f088a8ef821b7d75d2622948 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Wed, 2 Jan 2013 20:56:30 +0100 Subject: [PATCH 54/89] Warning fixes, prevent a possible (but unlikely) crash --- Core/HLE/sceCtrl.cpp | 2 +- Core/HLE/sceKernelInterrupt.h | 4 ++-- Core/HLE/sceKernelThread.cpp | 12 +++++++++--- GPU/GPUCommon.h | 4 ++-- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Core/HLE/sceCtrl.cpp b/Core/HLE/sceCtrl.cpp index d8998af521..9a89bdd39c 100644 --- a/Core/HLE/sceCtrl.cpp +++ b/Core/HLE/sceCtrl.cpp @@ -361,7 +361,7 @@ u32 sceCtrlSetSamplingMode(u32 mode) int sceCtrlGetSamplingMode(u32 modePtr) { u32 retVal = analogEnabled == true ? CTRL_MODE_ANALOG : CTRL_MODE_DIGITAL; - DEBUG_LOG(HLE, "%d=sceCtrlGetSamplingMode(%i)", retVal); + DEBUG_LOG(HLE, "%d=sceCtrlGetSamplingMode(%08x)", retVal, modePtr); if (Memory::IsValidAddress(modePtr)) Memory::Write_U32(retVal, modePtr); diff --git a/Core/HLE/sceKernelInterrupt.h b/Core/HLE/sceKernelInterrupt.h index 6b60a7870f..461c5153ea 100644 --- a/Core/HLE/sceKernelInterrupt.h +++ b/Core/HLE/sceKernelInterrupt.h @@ -71,10 +71,10 @@ struct PendingInterrupt { PendingInterrupt(int intr_, int subintr_, int arg_) : intr(intr_), subintr(subintr_), hasArg(true), arg(arg_) {} - int arg; - bool hasArg; int intr; int subintr; + bool hasArg; + int arg; }; class SubIntrHandler diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 70b86778b0..cd7b4fbb4b 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -1140,9 +1140,15 @@ void sceKernelCheckThreadStack() { u32 error; Thread *t = kernelObjects.Get(__KernelGetCurThread(), error); - u32 diff = abs((long)((s64)t->stackBlock - (s64)currentMIPS->r[MIPS_REG_SP])); - ERROR_LOG(HLE, "%i=sceKernelCheckThreadStack()", diff); - RETURN(diff); //Blatant lie + if (t) { + u32 diff = abs((long)((s64)t->stackBlock - (s64)currentMIPS->r[MIPS_REG_SP])); + WARN_LOG(HLE, "%i=sceKernelCheckThreadStack()", diff); + RETURN(diff); + } else { + // WTF? + ERROR_LOG(HLE, "sceKernelCheckThreadStack() - not on thread"); + RETURN(-1); + } } void ThreadContext::reset() diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index fbd55fd005..803f63efd5 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -9,8 +9,8 @@ public: dlIdGenerator(1), currentList(NULL), stackptr(0), - dumpThisFrame_(false), - dumpNextFrame_(false) + dumpNextFrame_(false), + dumpThisFrame_(false) {} virtual void PreExecuteOp(u32 op, u32 diff); From 28684a3ba26f1758a312fe85a9609646fc528bc1 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Wed, 2 Jan 2013 20:59:51 +0100 Subject: [PATCH 55/89] Upgrade submodules --- native | 2 +- pspautotests | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/native b/native index 1556328129..74057385bf 160000 --- a/native +++ b/native @@ -1 +1 @@ -Subproject commit 15563281297adb62c8e690fc063a9bf4442fcfc7 +Subproject commit 74057385bfc3baae81b3e35266596d031a196067 diff --git a/pspautotests b/pspautotests index f11966e358..3f1dc654e6 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit f11966e35825acce606f284f5485b21d6ea44c55 +Subproject commit 3f1dc654e66c37098169881e7d6437db3157dff8 From 883f61e3ddafc0de17cb78f355f860e8ce4406a6 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Wed, 2 Jan 2013 21:00:10 +0100 Subject: [PATCH 56/89] Savestates: Add quicksave/quickload. Add Android UI for savestates. All single slot for now. --- Common/StringUtil.cpp | 8 ++ Common/StringUtil.h | 2 + Core/Config.cpp | 3 +- Core/Dialog/SavedataParam.cpp | 14 ++-- Core/ELF/ParamSFO.cpp | 14 ++-- Core/ELF/ParamSFO.h | 3 +- Core/FileSystems/BlockDevices.h | 22 +++--- Core/FileSystems/DirectoryFileSystem.cpp | 5 ++ Core/FileSystems/DirectoryFileSystem.h | 1 + Core/FileSystems/FileSystem.h | 2 + Core/FileSystems/ISOFileSystem.h | 38 ++++----- Core/FileSystems/MetaFileSystem.cpp | 16 ++-- Core/FileSystems/MetaFileSystem.h | 3 + Core/HLE/sceKernel.cpp | 2 +- Core/PSPLoaders.cpp | 5 +- Core/SaveState.cpp | 98 +++++++++++++++++++++--- Core/SaveState.h | 16 +++- Core/System.cpp | 4 +- Core/System.h | 2 + Windows/WndMainWindow.cpp | 38 +++++++-- Windows/WndMainWindow.h | 2 +- Windows/ppsspp.rc | 12 +-- Windows/resource.h | 8 +- android/jni/MenuScreens.cpp | 36 +++++++-- android/jni/NativeApp.cpp | 4 + 25 files changed, 267 insertions(+), 91 deletions(-) diff --git a/Common/StringUtil.cpp b/Common/StringUtil.cpp index 8d96eae2b8..ae0a09b0c4 100644 --- a/Common/StringUtil.cpp +++ b/Common/StringUtil.cpp @@ -376,3 +376,11 @@ std::string UriEncode(const std::string & sSrc) delete [] pStart; return sResult; } + +bool StringEndsWith(std::string const &fullString, std::string const &ending) { + if (fullString.length() >= ending.length()) { + return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending)); + } else { + return false; + } +} diff --git a/Common/StringUtil.h b/Common/StringUtil.h index a5477a3996..b4282c3533 100644 --- a/Common/StringUtil.h +++ b/Common/StringUtil.h @@ -129,4 +129,6 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st std::string UriDecode(const std::string & sSrc); std::string UriEncode(const std::string & sSrc); +bool StringEndsWith(std::string const &fullString, std::string const &ending); + #endif // _STRINGUTIL_H_ diff --git a/Core/Config.cpp b/Core/Config.cpp index e0ea8cff4e..113860c86a 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -59,7 +59,7 @@ void CConfig::Load(const char *iniFileName) graphics->Get("DisplayFramebuffer", &bDisplayFramebuffer, false); graphics->Get("WindowZoom", &iWindowZoom, 1); graphics->Get("BufferedRendering", &bBufferedRendering, true); - graphics->Get("HardwareTransform", &bHardwareTransform, false); + graphics->Get("HardwareTransform", &bHardwareTransform, true); graphics->Get("LinearFiltering", &bLinearFiltering, false); IniFile::Section *sound = iniFile.GetOrCreateSection("Sound"); @@ -69,7 +69,6 @@ void CConfig::Load(const char *iniFileName) control->Get("ShowStick", &bShowAnalogStick, false); control->Get("ShowTouchControls", &bShowTouchControls, true); - // Ephemeral settings bDrawWireframe = false; } diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index 0c34ce9e63..24b187a025 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -226,8 +226,8 @@ bool SavedataParam::Save(SceUtilitySavedataParam* param, int saveId) PSPFileInfo sfoInfo = pspFileSystem.GetFileInfo(sfopath); if(sfoInfo.exists) // Read old sfo if exist { - u8 *sfoData = new u8[sfoInfo.size]; - size_t sfoSize = sfoInfo.size; + u8 *sfoData = new u8[(size_t)sfoInfo.size]; + size_t sfoSize = (size_t)sfoInfo.size; if(ReadPSPFile(sfopath,sfoData,sfoSize)) { sfoFile.ReadSFO(sfoData,sfoSize); @@ -475,7 +475,7 @@ bool SavedataParam::GetList(SceUtilitySavedataParam *param) if (Memory::IsValidAddress(outputBuffer)) { std::string searchString = GetGameName(param)+GetSaveName(param); - for(int i = 0; i < allDir.size() && i < maxFile; i++) + for (size_t i = 0; i < allDir.size() && i < maxFile; i++) { std::string dirName = allDir[i].name; if(PSPMatch(dirName, searchString)) @@ -484,7 +484,7 @@ bool SavedataParam::GetList(SceUtilitySavedataParam *param) } } - for(int i = 0; i < validDir.size(); i++) + for (size_t i = 0; i < validDir.size(); i++) { u32 baseAddr = outputBuffer + (i*72); Memory::Write_U32(0x11FF,baseAddr + 0); // mode @@ -514,7 +514,7 @@ bool SavedataParam::GetFilesList(SceUtilitySavedataParam *param) } u32 dataAddr = param->fileListAddr; - if(!Memory::IsValidAddress(dataAddr)) + if (!Memory::IsValidAddress(dataAddr)) return false; // TODO : Need to be checked against more game @@ -524,7 +524,7 @@ bool SavedataParam::GetFilesList(SceUtilitySavedataParam *param) //for Valkyria2, dataAddr+0 and dataAddr+12 has "5" for 5 files int numFiles = Memory::Read_U32(dataAddr+12); int foundFiles = 0; - for(int i = 0; i < numFiles; i++) + for (int i = 0; i < numFiles; i++) { // for each file (80 bytes): // u32 mode, u32 ??, u64 size, u64 ctime, u64 ??, u64 atime, u64 ???, u64 mtime, u64 ??? @@ -535,7 +535,7 @@ bool SavedataParam::GetFilesList(SceUtilitySavedataParam *param) strncpy(fileName, Memory::GetCharPointer(curFileInfoAddr + 64),16); std::string filePath = savePath + GetGameName(param) + GetSaveName(param) + "/" + fileName; PSPFileInfo info = pspFileSystem.GetFileInfo(filePath); - if(info.exists) + if (info.exists) { Memory::Write_U32(0x21FF, curFileInfoAddr+0); Memory::Write_U64(info.size, curFileInfoAddr+8); diff --git a/Core/ELF/ParamSFO.cpp b/Core/ELF/ParamSFO.cpp index 7965c1455b..bfba51a6cd 100644 --- a/Core/ELF/ParamSFO.cpp +++ b/Core/ELF/ParamSFO.cpp @@ -147,7 +147,7 @@ bool ParamSFOData::WriteSFO(u8 **paramsfo, size_t *size) total_size += sizeof(Header); // Get size info - for(std::map::iterator it = values.begin(); it != values.end(); it++) + for (std::map::iterator it = values.begin(); it != values.end(); it++) { key_size += it->first.size()+1; data_size += it->second.max_size; @@ -168,29 +168,29 @@ bool ParamSFOData::WriteSFO(u8 **paramsfo, size_t *size) u8* data = new u8[total_size]; *paramsfo = data; - memset(data,0,total_size); - memcpy(data,&header,sizeof(Header)); + memset(data, 0, total_size); + memcpy(data, &header, sizeof(Header)); // Now fill IndexTable *index_ptr = (IndexTable*)(data + sizeof(Header)); u8* key_ptr = data + header.key_table_start; u8* data_ptr = data + header.data_table_start; - for(std::map::iterator it = values.begin(); it != values.end(); it++) + for (std::map::iterator it = values.begin(); it != values.end(); it++) { u16 offset = (u16)(key_ptr - (data+header.key_table_start)); index_ptr->key_table_offset = offset; offset = (u16)(data_ptr - (data+header.data_table_start)); index_ptr->data_table_offset = offset; index_ptr->param_max_len = it->second.max_size; - if(it->second.type == VT_INT) + if (it->second.type == VT_INT) { index_ptr->param_fmt = 0x0404; index_ptr->param_len = 4; *(int*)data_ptr = it->second.i_value; } - else if(it->second.type == VT_UTF8_SPE) + else if (it->second.type == VT_UTF8_SPE) { index_ptr->param_fmt = 0x0004; index_ptr->param_len = it->second.u_size; @@ -198,7 +198,7 @@ bool ParamSFOData::WriteSFO(u8 **paramsfo, size_t *size) memset(data_ptr,0,index_ptr->param_max_len); memcpy(data_ptr,it->second.u_value,index_ptr->param_len); } - else if(it->second.type == VT_UTF8) + else if (it->second.type == VT_UTF8) { index_ptr->param_fmt = 0x0204; index_ptr->param_len = it->second.s_value.size()+1; diff --git a/Core/ELF/ParamSFO.h b/Core/ELF/ParamSFO.h index 5f842dfecf..1620563dd0 100644 --- a/Core/ELF/ParamSFO.h +++ b/Core/ELF/ParamSFO.h @@ -33,14 +33,15 @@ public: bool ReadSFO(const u8 *paramsfo, size_t size); bool WriteSFO(u8 **paramsfo, size_t *size); -private: +private: enum ValueType { VT_INT, VT_UTF8, VT_UTF8_SPE // raw data in u8 }; + class ValueData { public: diff --git a/Core/FileSystems/BlockDevices.h b/Core/FileSystems/BlockDevices.h index 626c11e6ed..48faa59cad 100644 --- a/Core/FileSystems/BlockDevices.h +++ b/Core/FileSystems/BlockDevices.h @@ -38,28 +38,32 @@ public: class CISOFileBlockDevice : public BlockDevice { +public: + CISOFileBlockDevice(std::string _filename); + ~CISOFileBlockDevice(); + bool ReadBlock(int blockNumber, u8 *outPtr); + int GetNumBlocks() { return numBlocks;} + +private: std::string filename; FILE *f; u32 *index; int indexShift; u32 blockSize; int numBlocks; -public: - CISOFileBlockDevice(std::string _filename); - ~CISOFileBlockDevice(); - bool ReadBlock(int blockNumber, u8 *outPtr); - int GetNumBlocks() { return numBlocks;} }; class FileBlockDevice : public BlockDevice { - std::string filename; - FILE *f; - size_t filesize; public: FileBlockDevice(std::string _filename); ~FileBlockDevice(); bool ReadBlock(int blockNumber, u8 *outPtr); - int GetNumBlocks() {return (int)(filesize/GetBlockSize());} + int GetNumBlocks() {return (int)(filesize / GetBlockSize());} + +private: + std::string filename; + FILE *f; + size_t filesize; }; diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp index cbf7bb9e80..523661e9fd 100644 --- a/Core/FileSystems/DirectoryFileSystem.cpp +++ b/Core/FileSystems/DirectoryFileSystem.cpp @@ -510,6 +510,11 @@ PSPFileInfo DirectoryFileSystem::GetFileInfo(std::string filename) { return x; } +bool DirectoryFileSystem::GetHostPath(const std::string &inpath, std::string &outpath) { + outpath = GetLocalPath(inpath); + return true; +} + std::vector DirectoryFileSystem::GetDirListing(std::string path) { std::vector myVector; #ifdef _WIN32 diff --git a/Core/FileSystems/DirectoryFileSystem.h b/Core/FileSystems/DirectoryFileSystem.h index 6cb334fc53..739a8427ad 100644 --- a/Core/FileSystems/DirectoryFileSystem.h +++ b/Core/FileSystems/DirectoryFileSystem.h @@ -67,6 +67,7 @@ public: bool RmDir(const std::string &dirname); bool RenameFile(const std::string &from, const std::string &to); bool DeleteFile(const std::string &filename); + bool GetHostPath(const std::string &inpath, std::string &outpath); private: struct OpenFileEntry { diff --git a/Core/FileSystems/FileSystem.h b/Core/FileSystems/FileSystem.h index 4d8670effd..87fc1b3f83 100644 --- a/Core/FileSystems/FileSystem.h +++ b/Core/FileSystems/FileSystem.h @@ -103,6 +103,7 @@ public: virtual bool RmDir(const std::string &dirname) = 0; virtual bool RenameFile(const std::string &from, const std::string &to) = 0; virtual bool DeleteFile(const std::string &filename) = 0; + virtual bool GetHostPath(const std::string &inpath, std::string &outpath) = 0; }; @@ -122,6 +123,7 @@ public: virtual bool RmDir(const std::string &dirname) {return false;} virtual bool RenameFile(const std::string &from, const std::string &to) {return false;} virtual bool DeleteFile(const std::string &filename) {return false;} + virtual bool GetHostPath(const std::string &inpath, std::string &outpath) {return false;} }; diff --git a/Core/FileSystems/ISOFileSystem.h b/Core/FileSystems/ISOFileSystem.h index f07b25850d..ab90080829 100644 --- a/Core/FileSystems/ISOFileSystem.h +++ b/Core/FileSystems/ISOFileSystem.h @@ -27,6 +27,26 @@ class ISOFileSystem : public IFileSystem { +public: + ISOFileSystem(IHandleAllocator *_hAlloc, BlockDevice *_blockDevice); + ~ISOFileSystem(); + void DoState(PointerWrap &p); + std::vector GetDirListing(std::string path); + u32 OpenFile(std::string filename, FileAccess access); + void CloseFile(u32 handle); + size_t ReadFile(u32 handle, u8 *pointer, s64 size); + size_t SeekFile(u32 handle, s32 position, FileMove type); + PSPFileInfo GetFileInfo(std::string filename); + bool OwnsHandle(u32 handle); + + size_t WriteFile(u32 handle, const u8 *pointer, s64 size); + bool GetHostPath(const std::string &inpath, std::string &outpath) {return false;} + virtual bool MkDir(const std::string &dirname) {return false;} + virtual bool RmDir(const std::string &dirname) {return false;} + virtual bool RenameFile(const std::string &from, const std::string &to) {return false;} + virtual bool DeleteFile(const std::string &filename) {return false;} + +private: struct TreeEntry { TreeEntry(){} @@ -69,22 +89,4 @@ class ISOFileSystem : public IFileSystem void ReadDirectory(u32 startsector, u32 dirsize, TreeEntry *root); TreeEntry *GetFromPath(std::string path, bool catchError=true); std::string EntryFullPath(TreeEntry *e); - -public: - ISOFileSystem(IHandleAllocator *_hAlloc, BlockDevice *_blockDevice); - ~ISOFileSystem(); - void DoState(PointerWrap &p); - std::vector GetDirListing(std::string path); - u32 OpenFile(std::string filename, FileAccess access); - void CloseFile(u32 handle); - size_t ReadFile(u32 handle, u8 *pointer, s64 size); - size_t WriteFile(u32 handle, const u8 *pointer, s64 size); - size_t SeekFile(u32 handle, s32 position, FileMove type); - PSPFileInfo GetFileInfo(std::string filename); - bool OwnsHandle(u32 handle); - - virtual bool MkDir(const std::string &dirname) {return false;} - virtual bool RmDir(const std::string &dirname) {return false;} - virtual bool RenameFile(const std::string &from, const std::string &to) {return false;} - virtual bool DeleteFile(const std::string &filename) {return false;} }; diff --git a/Core/FileSystems/MetaFileSystem.cpp b/Core/FileSystems/MetaFileSystem.cpp index 58ae33fae1..ad144396d8 100644 --- a/Core/FileSystems/MetaFileSystem.cpp +++ b/Core/FileSystems/MetaFileSystem.cpp @@ -16,6 +16,7 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include +#include "Common/StringUtil.h" #include "MetaFileSystem.h" static bool ApplyPathStringToComponentsVector(std::vector &vector, const std::string &pathString) @@ -251,14 +252,15 @@ PSPFileInfo MetaFileSystem::GetFileInfo(std::string filename) } } -//TODO: Not sure where this should live. Seems a bit wrong putting it in common -bool stringEndsWith (std::string const &fullString, std::string const &ending) +bool MetaFileSystem::GetHostPath(const std::string &inpath, std::string &outpath) { - if (fullString.length() >= ending.length()) { - return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending)); - } else { - return false; - } + std::string of; + IFileSystem *system; + if (MapFilePath(inpath, of, &system)) { + return system->GetHostPath(of, outpath); + } else { + return false; + } } std::vector MetaFileSystem::GetDirListing(std::string path) diff --git a/Core/FileSystems/MetaFileSystem.h b/Core/FileSystems/MetaFileSystem.h index 7fd0a96db2..88fc50d23c 100644 --- a/Core/FileSystems/MetaFileSystem.h +++ b/Core/FileSystems/MetaFileSystem.h @@ -41,6 +41,9 @@ public: IFileSystem *GetHandleOwner(u32 handle); bool MapFilePath(const std::string &inpath, std::string &outpath, IFileSystem **system); + // Only possible if a file system is a DirectoryFileSystem or similar. + bool GetHostPath(const std::string &inpath, std::string &outpath); + std::vector GetDirListing(std::string path); u32 OpenFile(std::string filename, FileAccess access); void CloseFile(u32 handle); diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index 94eebea14a..e21876fd41 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -78,7 +78,6 @@ void __KernelInit() return; } - SaveState::Init(); __KernelTimeInit(); __InterruptsInit(); __KernelMemoryInit(); @@ -101,6 +100,7 @@ void __KernelInit() __ImposeInit(); __UsbInit(); __FontInit(); + SaveState::Init(); // Must be after IO, as it may create a directory // "Internal" PSP libraries __PPGeInit(); diff --git a/Core/PSPLoaders.cpp b/Core/PSPLoaders.cpp index afc8cad456..7915b80d66 100644 --- a/Core/PSPLoaders.cpp +++ b/Core/PSPLoaders.cpp @@ -77,11 +77,10 @@ bool Load_PSP_ISO(const char *filename, std::string *error_string) u32 fd = pspFileSystem.OpenFile(sfoPath, FILEACCESS_READ); pspFileSystem.ReadFile(fd, paramsfo, fileInfo.size); pspFileSystem.CloseFile(fd); - ParamSFOData data; - if (data.ReadSFO(paramsfo, (size_t)fileInfo.size)) + if (g_paramSFO.ReadSFO(paramsfo, (size_t)fileInfo.size)) { char title[1024]; - sprintf(title, "%s : %s", data.GetValueString("DISC_ID").c_str(), data.GetValueString("TITLE").c_str()); + sprintf(title, "%s : %s", g_paramSFO.GetValueString("DISC_ID").c_str(), g_paramSFO.GetValueString("TITLE").c_str()); INFO_LOG(LOADER, "%s", title); host->SetWindowTitle(title); } diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index 11f5945c10..215dda6451 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -16,6 +16,7 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "../Common/StdMutex.h" +#include "../Common/FileUtil.h" #include #include "SaveState.h" @@ -45,14 +46,15 @@ namespace SaveState struct Operation { - Operation(OperationType t, const std::string &f, Callback cb) - : type(t), filename(f), callback(cb) + Operation(OperationType t, const std::string &f, Callback cb, void *cbUserData_) + : type(t), filename(f), callback(cb), cbUserData(cbUserData_) { } OperationType type; std::string filename; Callback callback; + void *cbUserData; }; static int timer; @@ -61,7 +63,6 @@ namespace SaveState void Process(u64 userdata, int cyclesLate); - // This is where the magic happens. void SaveStart::DoState(PointerWrap &p) { // Gotta do CoreTiming first since we'll restore into it. @@ -96,19 +97,94 @@ namespace SaveState CoreTiming::ScheduleEvent_Threadsafe(0, timer); } - void Load(const std::string &filename, Callback callback) + void Load(const std::string &filename, Callback callback, void *cbUserData) { - Enqueue(Operation(SAVESTATE_LOAD, filename, callback)); + Enqueue(Operation(SAVESTATE_LOAD, filename, callback, cbUserData)); } - void Save(const std::string &filename, Callback callback) + void Save(const std::string &filename, Callback callback, void *cbUserData) { - Enqueue(Operation(SAVESTATE_SAVE, filename, callback)); + Enqueue(Operation(SAVESTATE_SAVE, filename, callback, cbUserData)); } - void Verify(Callback callback) + + // Slot utilities + + std::string GenerateSaveSlotFilename(int slot) { - Enqueue(Operation(SAVESTATE_VERIFY, std::string(""), callback)); + char discID[256]; + char temp[256]; + sprintf(discID, "%s_%s", + g_paramSFO.GetValueString("DISC_ID").c_str(), + g_paramSFO.GetValueString("DISC_VERSION").c_str()); + sprintf(temp, "ms0:/PSP/PPSSPP_STATE/%s_%i.ppst", discID, slot); + std::string hostPath; + if (pspFileSystem.GetHostPath(std::string(temp), hostPath)) { + return hostPath; + } else { + return ""; + } + } + + void LoadSlot(int slot, Callback callback, void *cbUserData) + { + std::string fn = GenerateSaveSlotFilename(slot); + if (!fn.empty()) + Load(fn, callback, cbUserData); + else + (*callback)(false, cbUserData); + } + + void SaveSlot(int slot, Callback callback, void *cbUserData) + { + std::string fn = GenerateSaveSlotFilename(slot); + if (!fn.empty()) + Save(fn, callback, cbUserData); + else + (*callback)(false, cbUserData); + } + + void HasSaveInSlot(int slot) + { + std::string fn = GenerateSaveSlotFilename(slot); + } + + bool operator < (const tm &t1, const tm &t2) { + if (t1.tm_year < t2.tm_year) return true; + if (t1.tm_year > t2.tm_year) return false; + if (t1.tm_mon < t2.tm_mon) return true; + if (t1.tm_mon > t2.tm_mon) return false; + if (t1.tm_mday < t2.tm_mday) return true; + if (t1.tm_mday > t2.tm_mday) return false; + if (t1.tm_hour < t2.tm_hour) return true; + if (t1.tm_hour > t2.tm_hour) return false; + if (t1.tm_min < t2.tm_min) return true; + if (t1.tm_min > t2.tm_min) return false; + if (t1.tm_sec < t2.tm_sec) return true; + if (t1.tm_sec > t2.tm_sec) return false; + return false; + } + + int GetMostRecentSaveSlot() { + int newestSlot = -1; + tm newestDate = {0}; + for (int i = 0; i < SAVESTATESLOTS; i++) { + std::string fn = GenerateSaveSlotFilename(i); + if (File::Exists(fn)) { + tm time = File::GetModifTime(fn); + if (newestDate < time) { + newestDate = time; + newestSlot = i; + } + } + } + return newestSlot; + } + + + void Verify(Callback callback, void *cbUserData) + { + Enqueue(Operation(SAVESTATE_VERIFY, std::string(""), callback, cbUserData)); } std::vector Flush() @@ -164,12 +240,14 @@ namespace SaveState } if (op.callback != NULL) - op.callback(result); + op.callback(result, op.cbUserData); } } void Init() { timer = CoreTiming::RegisterEvent("SaveState", Process); + // Make sure there's a directory for save slots + pspFileSystem.MkDir("ms0:/PSP/PPSSPP_STATE"); } } diff --git a/Core/SaveState.h b/Core/SaveState.h index 82a7021040..2edecfe930 100644 --- a/Core/SaveState.h +++ b/Core/SaveState.h @@ -20,20 +20,28 @@ namespace SaveState { - typedef void (*Callback)(bool status); + typedef void (*Callback)(bool status, void *cbUserData); // TODO: Better place for this? const int REVISION = 1; + const int SAVESTATESLOTS = 4; void Init(); + void SaveSlot(int slot, Callback callback, void *cbUserData = 0); + void LoadSlot(int slot, Callback callback, void *cbUserData = 0); + void HasSaveInSlot(int slot); + int GetNewestSlot(); + // Load the specified file into the current state (async.) // Warning: callback will be called on a different thread. - void Load(const std::string &filename, Callback callback = NULL); + void Load(const std::string &filename, Callback callback = 0, void *cbUserData = 0); + // Save the current state to the specified file (async.) // Warning: callback will be called on a different thread. - void Save(const std::string &filename, Callback callback = NULL); + void Save(const std::string &filename, Callback callback = 0, void *cbUserData = 0); + // For testing / automated tests. Runs a save state verification pass (async.) // Warning: callback will be called on a different thread. - void Verify(Callback callback = NULL); + void Verify(Callback callback = 0, void *cbUserData = 0); }; diff --git a/Core/System.cpp b/Core/System.cpp index 9110dcc245..67c3b74cd6 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -37,10 +37,10 @@ #include "CoreParameter.h" #include "FileSystems/MetaFileSystem.h" #include "Loaders.h" - +#include "ELF/ParamSFO.h" MetaFileSystem pspFileSystem; - +ParamSFOData g_paramSFO; static CoreParameter coreParameter; bool PSP_Init(const CoreParameter &coreParam, std::string *error_string) diff --git a/Core/System.h b/Core/System.h index a3340b2a21..a47d1622fe 100644 --- a/Core/System.h +++ b/Core/System.h @@ -21,8 +21,10 @@ #include "MemMap.h" #include "FileSystems/MetaFileSystem.h" #include "CoreParameter.h" +#include "ELF/ParamSFO.h" extern MetaFileSystem pspFileSystem; +extern ParamSFOData g_paramSFO; bool PSP_Init(const CoreParameter &coreParam, std::string *error_string); bool PSP_IsInited(); diff --git a/Windows/WndMainWindow.cpp b/Windows/WndMainWindow.cpp index f6442f8315..beec2a68c8 100644 --- a/Windows/WndMainWindow.cpp +++ b/Windows/WndMainWindow.cpp @@ -312,7 +312,7 @@ namespace MainWindow UpdateMenus(); break; - case ID_FILE_LOADSTATE: + case ID_FILE_LOADSTATEFILE: if (g_State.bEmuThreadStarted) { nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING; @@ -327,7 +327,7 @@ namespace MainWindow } break; - case ID_FILE_SAVESTATE: + case ID_FILE_SAVESTATEFILE: if (g_State.bEmuThreadStarted) { nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING; @@ -342,6 +342,32 @@ namespace MainWindow } break; + // TODO: Add UI for multiple slots + + case ID_FILE_QUICKLOADSTATE: + if (g_State.bEmuThreadStarted) + { + nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING; + for (int i=0; iGetDlgHandle(), WM_COMMAND, IDC_STOP, 0); + } + SetCursor(LoadCursor(0,IDC_WAIT)); + SaveState::LoadSlot(0, SaveStateActionFinished); + break; + + case ID_FILE_QUICKSAVESTATE: + if (g_State.bEmuThreadStarted) + { + nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING; + for (int i=0; iGetDlgHandle(), WM_COMMAND, IDC_STOP, 0); + } + SetCursor(LoadCursor(0,IDC_WAIT)); + SaveState::SaveSlot(0, SaveStateActionFinished); + break; + case ID_OPTIONS_SCREEN1X: SetZoom(1); UpdateMenus(); @@ -675,8 +701,10 @@ namespace MainWindow enable = g_State.bEmuThreadStarted ? MF_GRAYED : MF_ENABLED; EnableMenuItem(menu,ID_FILE_LOAD,enable); - EnableMenuItem(menu,ID_FILE_SAVESTATE,!enable); - EnableMenuItem(menu,ID_FILE_LOADSTATE,!enable); + EnableMenuItem(menu,ID_FILE_SAVESTATEFILE,!enable); + EnableMenuItem(menu,ID_FILE_LOADSTATEFILE,!enable); + EnableMenuItem(menu,ID_FILE_QUICKSAVESTATE,!enable); + EnableMenuItem(menu,ID_FILE_QUICKLOADSTATE,!enable); EnableMenuItem(menu,ID_CPU_DYNAREC,enable); EnableMenuItem(menu,ID_CPU_INTERPRETER,enable); EnableMenuItem(menu,ID_CPU_FASTINTERPRETER,enable); @@ -788,7 +816,7 @@ namespace MainWindow } } - void SaveStateActionFinished(bool result) + void SaveStateActionFinished(bool result, void *userdata) { // TODO: Improve messaging? if (!result) diff --git a/Windows/WndMainWindow.h b/Windows/WndMainWindow.h index b58823ca25..11e7d4c2cb 100644 --- a/Windows/WndMainWindow.h +++ b/Windows/WndMainWindow.h @@ -17,7 +17,7 @@ namespace MainWindow void SetPlaying(const char*text); void BrowseAndBoot(); void SetNextState(CoreState state); - void SaveStateActionFinished(bool result); + void SaveStateActionFinished(bool result, void *userdata); void _ViewFullScreen(HWND hWnd); void _ViewNormal(HWND hWnd); } diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 0eafb5b937..11fcf4fd43 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -187,9 +187,11 @@ BEGIN MENUITEM "&Open...", ID_FILE_LOAD MENUITEM "&Close", ID_EMULATION_STOP MENUITEM SEPARATOR -MENUITEM "&Load State\tF4" ID_FILE_LOADSTATE -MENUITEM "&Save State\tF2" ID_FILE_SAVESTATE -MENUITEM SEPARATOR + MENUITEM "Quickload state\tF4" ID_FILE_QUICKLOADSTATE + MENUITEM "Quicksave state\tF2" ID_FILE_QUICKSAVESTATE + MENUITEM "&Load State File..." ID_FILE_LOADSTATEFILE + MENUITEM "&Save State File..." ID_FILE_SAVESTATEFILE + MENUITEM SEPARATOR MENUITEM "E&xit", ID_FILE_EXIT END POPUP "&Emulation" @@ -321,8 +323,8 @@ BEGIN "R", ID_DEBUG_REGISTERS, VIRTKEY, CONTROL, NOINVERT VK_F7, ID_EMULATION_RUN, VIRTKEY, NOINVERT VK_F8, ID_EMULATION_PAUSE, VIRTKEY, NOINVERT - VK_F2, ID_FILE_SAVESTATE, VIRTKEY, NOINVERT - VK_F4, ID_FILE_LOADSTATE, VIRTKEY, NOINVERT + VK_F2, ID_FILE_QUICKSAVESTATE, VIRTKEY, NOINVERT + VK_F4, ID_FILE_QUICKLOADSTATE, VIRTKEY, NOINVERT "1", ID_OPTIONS_SCREEN1X, VIRTKEY, CONTROL, NOINVERT "2", ID_OPTIONS_SCREEN2X, VIRTKEY, CONTROL, NOINVERT "3", ID_OPTIONS_SCREEN3X, VIRTKEY, CONTROL, NOINVERT diff --git a/Windows/resource.h b/Windows/resource.h index af56ef8446..79b18ad927 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -53,8 +53,8 @@ #define ID_DEBUG_BREAKPOINTS 122 #define ID_FILE_LOAD_BIN 123 #define ID_FILE_LOAD_ISO 125 -#define ID_FILE_LOADSTATE 126 -#define ID_FILE_SAVESTATE 127 +#define ID_FILE_LOADSTATEFILE 126 +#define ID_FILE_SAVESTATEFILE 127 #define ID_EMULATION_RESET 130 #define IDD_ABOUTBOX 133 #define ID_DEBUG_LOADMAPFILE 134 @@ -248,13 +248,15 @@ #define ID_OPTIONS_FASTMEMORY 40125 #define IDC_STEPHLE 40126 #define ID_OPTIONS_LINEARFILTERING 40127 +#define ID_FILE_QUICKSAVESTATE 40128 +#define ID_FILE_QUICKLOADSTATE 40129 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 232 -#define _APS_NEXT_COMMAND_VALUE 40127 +#define _APS_NEXT_COMMAND_VALUE 40130 #define _APS_NEXT_CONTROL_VALUE 1162 #define _APS_NEXT_SYMED_VALUE 101 #endif diff --git a/android/jni/MenuScreens.cpp b/android/jni/MenuScreens.cpp index b35ae132a7..1d22f0ac52 100644 --- a/android/jni/MenuScreens.cpp +++ b/android/jni/MenuScreens.cpp @@ -29,6 +29,7 @@ #include "ui/ui.h" #include "ui_atlas.h" #include "util/random/rng.h" +#include "util/text/utf8.h" #include "UIShader.h" #include "../../GPU/ge_constants.h" @@ -36,10 +37,16 @@ #include "../../GPU/GPUInterface.h" #include "../../Core/Config.h" #include "../../Core/CoreParameter.h" +#include "../../Core/SaveState.h" #include "MenuScreens.h" #include "EmuScreen.h" + +// Ugly communication with NativeApp +extern std::string game_title; + + static const int symbols[4] = { I_CROSS, I_CIRCLE, @@ -207,22 +214,39 @@ void InGameMenuScreen::render() { UIBegin(); DrawBackground(1.0f); - ui_draw2d.DrawText(UBUNTU48, "Emulation Paused", dp_xres / 2, 30, 0xFFFFFFFF, ALIGN_HCENTER); + const char *title; + if (UTF8StringHasNonASCII(game_title.c_str())) { + title = "(can't display japanese title)"; + } else { + title = game_title.c_str(); + } + + ui_draw2d.DrawText(UBUNTU48, title, dp_xres / 2, 30, 0xFFFFFFFF, ALIGN_HCENTER); int x = 30; int y = 50; - UICheckBox(GEN_ID, x, y += 50, "Show Debug Statistics (experimental)", ALIGN_TOPLEFT, &g_Config.bShowDebugStats); - UICheckBox(GEN_ID, x, y += 50, "Hardware Transform (experimental)", ALIGN_TOPLEFT, &g_Config.bHardwareTransform); + UICheckBox(GEN_ID, x, y += 50, "Show Debug Statistics", ALIGN_TOPLEFT, &g_Config.bShowDebugStats); + UICheckBox(GEN_ID, x, y += 50, "Hardware Transform", ALIGN_TOPLEFT, &g_Config.bHardwareTransform); + + // TODO: Add UI for more than one slot. + VLinear vlinear1(x, y + 80, 20); + UIText(UBUNTU24, vlinear1, "Save states are experimental (and large)", 0xFFFFFFFF); + if (UIButton(GEN_ID, vlinear1, LARGE_BUTTON_WIDTH, "Save State", ALIGN_LEFT)) { + SaveState::SaveSlot(0, 0, 0); + screenManager()->finishDialog(this, DR_CANCEL); + } + if (UIButton(GEN_ID, vlinear1, LARGE_BUTTON_WIDTH, "Load State", ALIGN_LEFT)) { + SaveState::LoadSlot(0, 0, 0); + screenManager()->finishDialog(this, DR_CANCEL); + } VLinear vlinear(dp_xres - 10, 160, 20); if (UIButton(GEN_ID, vlinear, LARGE_BUTTON_WIDTH, "Continue", ALIGN_RIGHT)) { screenManager()->finishDialog(this, DR_CANCEL); } - if (UIButton(GEN_ID, vlinear, LARGE_BUTTON_WIDTH, "Return to Menu", ALIGN_RIGHT)) { screenManager()->finishDialog(this, DR_OK); } - if (UIButton(GEN_ID, vlinear, LARGE_BUTTON_WIDTH, "Dump Next Frame", ALIGN_RIGHT)) { gpu->DumpNextFrame(); } @@ -253,7 +277,7 @@ void SettingsScreen::render() { int y = 50; UICheckBox(GEN_ID, x, y += 50, "Sound Emulation", ALIGN_TOPLEFT, &g_Config.bEnableSound); UICheckBox(GEN_ID, x, y += 50, "Buffered Rendering (may fix flicker)", ALIGN_TOPLEFT, &g_Config.bBufferedRendering); - UICheckBox(GEN_ID, x, y += 50, "Hardware Transform (experimental)", ALIGN_TOPLEFT, &g_Config.bHardwareTransform); + UICheckBox(GEN_ID, x, y += 50, "Hardware Transform", ALIGN_TOPLEFT, &g_Config.bHardwareTransform); bool useFastInt = g_Config.iCpuCore == CPU_FASTINTERPRETER; UICheckBox(GEN_ID, x, y += 50, "Slightly faster interpreter (may crash)", ALIGN_TOPLEFT, &useFastInt); diff --git a/android/jni/NativeApp.cpp b/android/jni/NativeApp.cpp index cbec8230ac..9faf23f009 100644 --- a/android/jni/NativeApp.cpp +++ b/android/jni/NativeApp.cpp @@ -53,6 +53,7 @@ Texture *uiTexture; ScreenManager *screenManager; std::string config_filename; +std::string game_title; class AndroidLogger : public LogListener { @@ -112,6 +113,9 @@ public: virtual bool AttemptLoadSymbolMap() {return false;} virtual void ResetSymbolMap() {} virtual void AddSymbol(std::string name, u32 addr, u32 size, int type=0) {} + virtual void SetWindowTitle(const char *message) { + game_title = message; + } }; // globals From 363f158a0a746079e34c3fd381ae8ecea030a430 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Wed, 2 Jan 2013 21:11:24 +0100 Subject: [PATCH 57/89] Just warning fixes --- Core/Dialog/PSPSaveDialog.cpp | 2 +- Core/Dialog/SavedataParam.cpp | 2 +- Core/Dialog/SavedataParam.h | 5 ++--- Core/HLE/sceGe.cpp | 2 +- Core/HLE/sceKernelInterrupt.h | 4 ++-- GPU/GLES/DisplayListInterpreter.cpp | 4 ++-- 6 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Core/Dialog/PSPSaveDialog.cpp b/Core/Dialog/PSPSaveDialog.cpp index 05afc27d54..675d3ec9ae 100644 --- a/Core/Dialog/PSPSaveDialog.cpp +++ b/Core/Dialog/PSPSaveDialog.cpp @@ -22,8 +22,8 @@ PSPSaveDialog::PSPSaveDialog() : PSPDialog() - , currentSelectedSave(0) , display(DS_NONE) + , currentSelectedSave(0) { param.SetPspParam(0); } diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index 24b187a025..84596e16eb 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -114,8 +114,8 @@ SavedataParam::SavedataParam() : pspParam(0) , selectedSave(0) , saveDataList(0) - , saveNameListDataCount(0) , saveDataListCount(0) + , saveNameListDataCount(0) { } diff --git a/Core/Dialog/SavedataParam.h b/Core/Dialog/SavedataParam.h index 702dc8b5d4..c79d83d8f5 100644 --- a/Core/Dialog/SavedataParam.h +++ b/Core/Dialog/SavedataParam.h @@ -144,6 +144,8 @@ struct SaveFileInfo class SavedataParam { public: + SavedataParam(); + static void Init(); std::string GetSaveFilePath(SceUtilitySavedataParam* param, int saveId = -1); std::string GetSaveDir(SceUtilitySavedataParam* param, int saveId = -1); @@ -161,8 +163,6 @@ public: static std::string GetSpaceText(int size); - SavedataParam(); - int SetPspParam(SceUtilitySavedataParam* param); SceUtilitySavedataParam* GetPspParam(); @@ -184,5 +184,4 @@ private: SaveFileInfo* saveDataList; int saveDataListCount; int saveNameListDataCount; - }; diff --git a/Core/HLE/sceGe.cpp b/Core/HLE/sceGe.cpp index a0caa81b15..a784728051 100644 --- a/Core/HLE/sceGe.cpp +++ b/Core/HLE/sceGe.cpp @@ -70,7 +70,7 @@ int __GeSubIntrBase(int callbackId) if (callbackId < 0) return 0; - if (callbackId >= ARRAY_SIZE(ge_used_callbacks)) + if (callbackId >= (int)(ARRAY_SIZE(ge_used_callbacks))) { WARN_LOG(HLE, "Unexpected (too high) GE callback id %d, ignoring", callbackId); return 0; diff --git a/Core/HLE/sceKernelInterrupt.h b/Core/HLE/sceKernelInterrupt.h index 461c5153ea..f93bbf2ca4 100644 --- a/Core/HLE/sceKernelInterrupt.h +++ b/Core/HLE/sceKernelInterrupt.h @@ -71,8 +71,8 @@ struct PendingInterrupt { PendingInterrupt(int intr_, int subintr_, int arg_) : intr(intr_), subintr(subintr_), hasArg(true), arg(arg_) {} - int intr; - int subintr; + u32 intr; + u32 subintr; bool hasArg; int arg; }; diff --git a/GPU/GLES/DisplayListInterpreter.cpp b/GPU/GLES/DisplayListInterpreter.cpp index 0c0ab11386..35f7109ea3 100644 --- a/GPU/GLES/DisplayListInterpreter.cpp +++ b/GPU/GLES/DisplayListInterpreter.cpp @@ -175,10 +175,10 @@ GLES_GPU::GLES_GPU(int renderWidth, int renderHeight) flushBeforeCommand_ = new u8[256]; memset(flushBeforeCommand_, 0, 256 * sizeof(bool)); - for (int i = 0; i < ARRAY_SIZE(flushOnChangedBeforeCommandList); i++) { + for (size_t i = 0; i < ARRAY_SIZE(flushOnChangedBeforeCommandList); i++) { flushBeforeCommand_[flushOnChangedBeforeCommandList[i]] = 2; } - for (int i = 0; i < ARRAY_SIZE(flushBeforeCommandList); i++) { + for (size_t i = 0; i < ARRAY_SIZE(flushBeforeCommandList); i++) { flushBeforeCommand_[flushBeforeCommandList[i]] = 1; } flushBeforeCommand_[1] = 0; From f956044d6c9c51fdbe0f72b44e4aeaca144ae314 Mon Sep 17 00:00:00 2001 From: TMaul Date: Tue, 1 Jan 2013 19:01:36 +0000 Subject: [PATCH 58/89] messing with the font init Still can't see why it never renders... --- Core/HLE/sceFont.cpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/Core/HLE/sceFont.cpp b/Core/HLE/sceFont.cpp index 13a3a08ab6..cfba0c0da0 100644 --- a/Core/HLE/sceFont.cpp +++ b/Core/HLE/sceFont.cpp @@ -271,6 +271,19 @@ int sceFontGetFontInfo(u32 fontHandle, u32 fontInfoPtr) fi.minGlyphCenterXF = 16; fi.minGlyphCenterXI = 16; fi.shadowMapLength = 0; + fi.fontStyle.fontAttributes=1; + fi.fontStyle.fontCountry= 1; + fi.fontStyle.fontExpire= 1; + fi.fontStyle.fontFamily= 1; + //fi.fontStyle.fontFileName="asd"; + fi.fontStyle.fontH=32; + fi.fontStyle.fontHRes=32; + fi.fontStyle.fontLanguage=1; + // fi.fontStyle.fontName="ppsspp"; + fi.fontStyle.fontRegion=9; + fi.fontStyle.fontV=32; + fi.fontStyle.fontVRes=32; + fi.fontStyle.fontWeight= 32; Memory::WriteStruct(fontInfoPtr, &fi); } @@ -316,7 +329,15 @@ int sceFontGetCharGlyphImage(u32 libHandler, u32 charCode, u32 glyphImagePtr) int bytesPerLine = Memory::Read_U16(glyphImagePtr+16); int buffer =Memory::Read_U32(glyphImagePtr+20); - Memory::Memset(buffer, 0x7F, bytesPerLine * bufHeight); + for (int y= 0; y < bufHeight; y++) + { + for (int x=0; x Date: Wed, 2 Jan 2013 20:26:52 +0000 Subject: [PATCH 59/89] Remove scesupPreAcc It's not really needed and is just going to get in the way... --- Core/Core.vcxproj | 2 -- Core/Core.vcxproj.filters | 6 ------ Core/HLE/HLETables.cpp | 1 - Core/HLE/scesupPreAcc.cpp | 38 -------------------------------------- Core/HLE/scesupPreAcc.h | 21 --------------------- 5 files changed, 68 deletions(-) delete mode 100644 Core/HLE/scesupPreAcc.cpp delete mode 100644 Core/HLE/scesupPreAcc.h diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 089671dfb9..3568d26aea 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -171,7 +171,6 @@ - @@ -319,7 +318,6 @@ - diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index d6bf753d66..3ee75bdfbe 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -318,9 +318,6 @@ HLE\Libraries - - HLE\Libraries - HLE\Libraries @@ -614,9 +611,6 @@ HLE\Libraries - - HLE\Libraries - HLE\Libraries diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp index 308e4e29f7..0aaf7f81bb 100644 --- a/Core/HLE/HLETables.cpp +++ b/Core/HLE/HLETables.cpp @@ -243,7 +243,6 @@ void RegisterAllModules() { Register_sceParseUri(); Register_sceSsl(); Register_sceParseHttp(); - Register_scesupPreAcc(); Register_sceVaudio(); Register_sceUsb(); diff --git a/Core/HLE/scesupPreAcc.cpp b/Core/HLE/scesupPreAcc.cpp deleted file mode 100644 index 564b656b39..0000000000 --- a/Core/HLE/scesupPreAcc.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2012- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#include "HLE.h" - -#include "scesupPreAcc.h" - -const HLEFunction scesupPreAcc[] = -{ - {0x110e318b, 0, "scesupPreAcc_0x110e318b"}, - {0x13ae25b3, 0, "scesupPreAcc_0x13ae25b3"}, - {0x28c5f696, 0, "scesupPreAcc_0x28c5f696"}, - {0x348ba3e2, 0, "scesupPreAcc_0x348ba3e2"}, - {0x86debd66, 0, "scesupPreAcc_0x86debd66"}, - {0xa0eaf444, 0, "scesupPreAcc_0xa0eaf444"}, - {0xb03ff882, 0, "scesupPreAcc_0xb03ff882"}, - {0x2ec3f4d9, 0, "scesupPreAcc_0x2ec3f4d9"}, - -}; - -void Register_scesupPreAcc() -{ - RegisterModule("scesupPreAcc",ARRAY_SIZE(scesupPreAcc), scesupPreAcc ); -} diff --git a/Core/HLE/scesupPreAcc.h b/Core/HLE/scesupPreAcc.h deleted file mode 100644 index 311e679bd8..0000000000 --- a/Core/HLE/scesupPreAcc.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2012- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#pragma once - -void Register_scesupPreAcc(); - From 1210efa51ac8b53c205e388a457b2a1faa67be0a Mon Sep 17 00:00:00 2001 From: TMaul Date: Wed, 2 Jan 2013 20:27:06 +0000 Subject: [PATCH 60/89] Fix mess in sceFont --- Core/HLE/sceFont.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Core/HLE/sceFont.cpp b/Core/HLE/sceFont.cpp index cfba0c0da0..f84c057089 100644 --- a/Core/HLE/sceFont.cpp +++ b/Core/HLE/sceFont.cpp @@ -337,8 +337,6 @@ int sceFontGetCharGlyphImage(u32 libHandler, u32 charCode, u32 glyphImagePtr) } } -// Memory::Memset(buffer, 0xff, bufWidth * bufHeight); - return 0; } From 399b8fb15d2b36abbd7cc4dcf8c21a0832032ea4 Mon Sep 17 00:00:00 2001 From: TMaul Date: Wed, 2 Jan 2013 20:30:02 +0000 Subject: [PATCH 61/89] And remove scesuppreacc from the makefiles as well --- CMakeLists.txt | 2 -- Core/CMakeLists.txt | 1 - Core/HLE/HLETables.cpp | 1 - android/jni/Android.mk | 1 - 4 files changed, 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f6d109a56d..6b96df6694 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -718,8 +718,6 @@ add_library(${CoreLibName} ${CoreLinkType} Core/HLE/sceSas.h Core/HLE/sceSsl.cpp Core/HLE/sceSsl.h - Core/HLE/scesupPreAcc.cpp - Core/HLE/scesupPreAcc.h Core/HLE/sceUmd.cpp Core/HLE/sceUmd.h Core/HLE/sceUsb.cpp diff --git a/Core/CMakeLists.txt b/Core/CMakeLists.txt index c96cec250a..a58c3ea077 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -61,7 +61,6 @@ set(SRCS HLE/sceSsl.cpp HLE/sceParseUri.cpp HLE/sceParseHttp.cpp - HLE/scesupPreAcc.cpp HLE/sceVaudio.cpp HW/MemoryStick.cpp HW/SasAudio.cpp diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp index 0aaf7f81bb..27f916faeb 100644 --- a/Core/HLE/HLETables.cpp +++ b/Core/HLE/HLETables.cpp @@ -51,7 +51,6 @@ #include "sceParseUri.h" #include "sceSsl.h" #include "sceParseHttp.h" -#include "scesupPreAcc.h" #include "sceVaudio.h" #include "sceUsb.h" diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 51c17d5f74..b5ab4fe4bb 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -148,7 +148,6 @@ LOCAL_SRC_FILES := \ $(SRC)/Core/HLE/sceUsb.cpp \ $(SRC)/Core/HLE/sceUtility.cpp \ $(SRC)/Core/HLE/sceVaudio.cpp \ - $(SRC)/Core/HLE/scesupPreAcc.cpp \ $(SRC)/Core/FileSystems/BlockDevices.cpp \ $(SRC)/Core/FileSystems/ISOFileSystem.cpp \ $(SRC)/Core/FileSystems/MetaFileSystem.cpp \ From dba01cb78ece2b71e21c347e189376a49710a15e Mon Sep 17 00:00:00 2001 From: TMaul Date: Wed, 2 Jan 2013 20:33:12 +0000 Subject: [PATCH 62/89] Re tabify --- Core/HLE/sceFont.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/HLE/sceFont.cpp b/Core/HLE/sceFont.cpp index f84c057089..98163f7ed2 100644 --- a/Core/HLE/sceFont.cpp +++ b/Core/HLE/sceFont.cpp @@ -279,7 +279,7 @@ int sceFontGetFontInfo(u32 fontHandle, u32 fontInfoPtr) fi.fontStyle.fontH=32; fi.fontStyle.fontHRes=32; fi.fontStyle.fontLanguage=1; - // fi.fontStyle.fontName="ppsspp"; + // fi.fontStyle.fontName="ppsspp"; fi.fontStyle.fontRegion=9; fi.fontStyle.fontV=32; fi.fontStyle.fontVRes=32; From 19b8ff5331f62575693fe93b17c38bdac772d163 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Wed, 2 Jan 2013 22:10:41 +0100 Subject: [PATCH 63/89] Use snappy to compress savestates. This is a bit of a hackjob sorry, will clean after 0.5. --- CMakeLists.txt | 13 +- Common/ChunkFile.h | 67 +- Core/Core.vcxproj | 7 + Core/Core.vcxproj.filters | 27 + Core/Dialog/SavedataParam.h | 2 +- android/jni/Android.mk | 2 + ext/snappy/AUTHORS | 1 + ext/snappy/COPYING | 28 + ext/snappy/readme.ppsspp.txt | 0 ext/snappy/snappy-c.cpp | 90 +++ ext/snappy/snappy-c.h | 138 ++++ ext/snappy/snappy-internal.h | 150 ++++ ext/snappy/snappy-sinksource.h | 137 ++++ ext/snappy/snappy-stubs-internal.h | 491 ++++++++++++ ext/snappy/snappy-stubs-public.h | 61 ++ ext/snappy/snappy.cpp | 1166 ++++++++++++++++++++++++++++ ext/snappy/snappy.h | 162 ++++ 17 files changed, 2526 insertions(+), 16 deletions(-) create mode 100644 ext/snappy/AUTHORS create mode 100644 ext/snappy/COPYING create mode 100644 ext/snappy/readme.ppsspp.txt create mode 100644 ext/snappy/snappy-c.cpp create mode 100644 ext/snappy/snappy-c.h create mode 100644 ext/snappy/snappy-internal.h create mode 100644 ext/snappy/snappy-sinksource.h create mode 100644 ext/snappy/snappy-stubs-internal.h create mode 100644 ext/snappy/snappy-stubs-public.h create mode 100644 ext/snappy/snappy.cpp create mode 100644 ext/snappy/snappy.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b96df6694..acc8d2611b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -273,6 +273,17 @@ add_library(zlib STATIC ) include_directories(ext/zlib) +add_library(snappy STATIC + ext/snappy/snappy-c.cpp + ext/snappy/snappy-internal.h + ext/snappy/snappy-sinksource.h + ext/snappy/snappy-stubs-internal.h + ext/snappy/snappy-stubs-public.h + ext/snappy/snappy.cpp + ext/snappy/snappy.h +) +include_directories(ext/snappy) + add_library(etcpack STATIC native/ext/etcpack/etcdec.cpp native/ext/etcpack/etcdec.h @@ -543,7 +554,7 @@ include_directories(native) # rapidxml is headers only so we can't make a lib specific for it include_directories(native/ext/rapidxml) target_link_libraries(native ${LIBZIP} etcpack sha1 stb_image stb_vorbis #vjson - zlib ${GLEW_LIBRARIES}) + zlib snappy ${GLEW_LIBRARIES}) if(ANDROID) target_link_libraries(native log) endif() diff --git a/Common/ChunkFile.h b/Common/ChunkFile.h index 1671cecc8a..d9866e3f8d 100644 --- a/Common/ChunkFile.h +++ b/Common/ChunkFile.h @@ -36,6 +36,7 @@ #include "Common.h" #include "FileUtil.h" +#include "../ext/snappy/snappy-c.h" template struct LinkedListItem : public T @@ -419,9 +420,22 @@ public: } u8 *ptr = buffer; + u8 *buf = buffer; + if (header.Compress) { + u8 *uncomp_buffer = new u8[header.UncompressedSize]; + size_t uncomp_size = header.UncompressedSize; + snappy_uncompress((const char *)buffer, sz, (char *)uncomp_buffer, &uncomp_size); + if (uncomp_size != header.UncompressedSize) { + ERROR_LOG(COMMON,"Size mismatch: file: %i calc: %i", (int)header.UncompressedSize, (int)uncomp_size); + } + ptr = uncomp_buffer; + buf = uncomp_buffer; + delete [] buffer; + } + PointerWrap p(&ptr, PointerWrap::MODE_READ); _class.DoState(p); - delete[] buffer; + delete[] buf; INFO_LOG(COMMON, "ChunkReader: Done loading %s" , _rFilename.c_str()); return true; @@ -439,33 +453,57 @@ public: return false; } + bool compress = true; + // Get data u8 *ptr = 0; PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); _class.DoState(p); size_t const sz = (size_t)ptr; - std::vector buffer(sz); + + u8 * buffer = new u8[sz]; ptr = &buffer[0]; p.SetMode(PointerWrap::MODE_WRITE); _class.DoState(p); - + // Create header SChunkHeader header; - header.Compress = 0; + header.Compress = compress ? 1 : 0; header.Revision = _Revision; header.ExpectedSize = (int)sz; + header.UncompressedSize = (int)sz; // Write to file - if (!pFile.WriteArray(&header, 1)) - { - ERROR_LOG(COMMON,"ChunkReader: Failed writing header"); - return false; - } - - if (!pFile.WriteBytes(&buffer[0], sz)) - { - ERROR_LOG(COMMON,"ChunkReader: Failed writing data"); - return false; + if (compress) { + size_t comp_len = snappy_max_compressed_length(sz); + u8 *compressed_buffer = new u8[comp_len]; + snappy_compress((const char *)buffer, sz, (char *)compressed_buffer, &comp_len); + delete [] buffer; + header.ExpectedSize = comp_len; + if (!pFile.WriteArray(&header, 1)) + { + ERROR_LOG(COMMON,"ChunkReader: Failed writing header"); + return false; + } + if (!pFile.WriteBytes(&compressed_buffer[0], comp_len)) { + ERROR_LOG(COMMON,"ChunkReader: Failed writing compressed data"); + return false; + } else { + INFO_LOG(COMMON, "Savestate: Compressed %i bytes into %i", (int)sz, (int)comp_len); + } + delete [] compressed_buffer; + } else { + if (!pFile.WriteArray(&header, 1)) + { + ERROR_LOG(COMMON,"ChunkReader: Failed writing header"); + return false; + } + if (!pFile.WriteBytes(&buffer[0], sz)) + { + ERROR_LOG(COMMON,"ChunkReader: Failed writing data"); + return false; + } + delete [] buffer; } INFO_LOG(COMMON,"ChunkReader: Done writing %s", @@ -503,6 +541,7 @@ private: int Revision; int Compress; int ExpectedSize; + int UncompressedSize; }; }; diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 3568d26aea..5c77d0b02e 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -116,6 +116,8 @@ + + @@ -259,6 +261,11 @@ + + + + + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 3ee75bdfbe..b87be99b6a 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -43,6 +43,12 @@ {41034c99-9b76-477f-8a77-bffaaffd5e82} + + {1966d4a4-9a34-4a6c-946a-ebaf33633276} + + + {0b77054f-7fc7-4c33-ada3-762aecde69e5} + @@ -348,6 +354,12 @@ Core + + Ext\Snappy + + + Ext\Snappy + @@ -641,6 +653,21 @@ Core + + Ext\Snappy + + + Ext\Snappy + + + Ext\Snappy + + + Ext\Snappy + + + Ext\Snappy + diff --git a/Core/Dialog/SavedataParam.h b/Core/Dialog/SavedataParam.h index c79d83d8f5..592c1d3bbc 100644 --- a/Core/Dialog/SavedataParam.h +++ b/Core/Dialog/SavedataParam.h @@ -140,7 +140,7 @@ struct SaveFileInfo int textureWidth; int textureHeight; }; - + class SavedataParam { public: diff --git a/android/jni/Android.mk b/android/jni/Android.mk index b5ab4fe4bb..53434f108f 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -53,6 +53,8 @@ LOCAL_SRC_FILES := \ $(SRC)/ext/libkirk/bn.c \ $(SRC)/ext/libkirk/ec.c \ $(SRC)/ext/libkirk/kirk_engine.c \ + $(SRC)/ext/snappy/snappy-c.cpp \ + $(SRC)/ext/snappy/snappy.cpp \ $(SRC)/Common/ArmABI.cpp \ $(SRC)/Common/ArmEmitter.cpp \ $(SRC)/Common/LogManager.cpp \ diff --git a/ext/snappy/AUTHORS b/ext/snappy/AUTHORS new file mode 100644 index 0000000000..4858b377c7 --- /dev/null +++ b/ext/snappy/AUTHORS @@ -0,0 +1 @@ +opensource@google.com diff --git a/ext/snappy/COPYING b/ext/snappy/COPYING new file mode 100644 index 0000000000..8d6bd9fed4 --- /dev/null +++ b/ext/snappy/COPYING @@ -0,0 +1,28 @@ +Copyright 2011, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/ext/snappy/readme.ppsspp.txt b/ext/snappy/readme.ppsspp.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ext/snappy/snappy-c.cpp b/ext/snappy/snappy-c.cpp new file mode 100644 index 0000000000..473a0b0978 --- /dev/null +++ b/ext/snappy/snappy-c.cpp @@ -0,0 +1,90 @@ +// Copyright 2011 Martin Gieseking . +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "snappy.h" +#include "snappy-c.h" + +extern "C" { + +snappy_status snappy_compress(const char* input, + size_t input_length, + char* compressed, + size_t *compressed_length) { + if (*compressed_length < snappy_max_compressed_length(input_length)) { + return SNAPPY_BUFFER_TOO_SMALL; + } + snappy::RawCompress(input, input_length, compressed, compressed_length); + return SNAPPY_OK; +} + +snappy_status snappy_uncompress(const char* compressed, + size_t compressed_length, + char* uncompressed, + size_t* uncompressed_length) { + size_t real_uncompressed_length; + if (!snappy::GetUncompressedLength(compressed, + compressed_length, + &real_uncompressed_length)) { + return SNAPPY_INVALID_INPUT; + } + if (*uncompressed_length < real_uncompressed_length) { + return SNAPPY_BUFFER_TOO_SMALL; + } + if (!snappy::RawUncompress(compressed, compressed_length, uncompressed)) { + return SNAPPY_INVALID_INPUT; + } + *uncompressed_length = real_uncompressed_length; + return SNAPPY_OK; +} + +size_t snappy_max_compressed_length(size_t source_length) { + return snappy::MaxCompressedLength(source_length); +} + +snappy_status snappy_uncompressed_length(const char *compressed, + size_t compressed_length, + size_t *result) { + if (snappy::GetUncompressedLength(compressed, + compressed_length, + result)) { + return SNAPPY_OK; + } else { + return SNAPPY_INVALID_INPUT; + } +} + +snappy_status snappy_validate_compressed_buffer(const char *compressed, + size_t compressed_length) { + if (snappy::IsValidCompressedBuffer(compressed, compressed_length)) { + return SNAPPY_OK; + } else { + return SNAPPY_INVALID_INPUT; + } +} + +} // extern "C" diff --git a/ext/snappy/snappy-c.h b/ext/snappy/snappy-c.h new file mode 100644 index 0000000000..c6c2a860a4 --- /dev/null +++ b/ext/snappy/snappy-c.h @@ -0,0 +1,138 @@ +/* + * Copyright 2011 Martin Gieseking . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Plain C interface (a wrapper around the C++ implementation). + */ + +#ifndef UTIL_SNAPPY_OPENSOURCE_SNAPPY_C_H_ +#define UTIL_SNAPPY_OPENSOURCE_SNAPPY_C_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* + * Return values; see the documentation for each function to know + * what each can return. + */ +typedef enum { + SNAPPY_OK = 0, + SNAPPY_INVALID_INPUT = 1, + SNAPPY_BUFFER_TOO_SMALL = 2 +} snappy_status; + +/* + * Takes the data stored in "input[0..input_length-1]" and stores + * it in the array pointed to by "compressed". + * + * signals the space available in "compressed". + * If it is not at least equal to "snappy_max_compressed_length(input_length)", + * SNAPPY_BUFFER_TOO_SMALL is returned. After successful compression, + * contains the true length of the compressed output, + * and SNAPPY_OK is returned. + * + * Example: + * size_t output_length = snappy_max_compressed_length(input_length); + * char* output = (char*)malloc(output_length); + * if (snappy_compress(input, input_length, output, &output_length) + * == SNAPPY_OK) { + * ... Process(output, output_length) ... + * } + * free(output); + */ +snappy_status snappy_compress(const char* input, + size_t input_length, + char* compressed, + size_t* compressed_length); + +/* + * Given data in "compressed[0..compressed_length-1]" generated by + * calling the snappy_compress routine, this routine stores + * the uncompressed data to + * uncompressed[0..uncompressed_length-1]. + * Returns failure (a value not equal to SNAPPY_OK) if the message + * is corrupted and could not be decrypted. + * + * signals the space available in "uncompressed". + * If it is not at least equal to the value returned by + * snappy_uncompressed_length for this stream, SNAPPY_BUFFER_TOO_SMALL + * is returned. After successful decompression, + * contains the true length of the decompressed output. + * + * Example: + * size_t output_length; + * if (snappy_uncompressed_length(input, input_length, &output_length) + * != SNAPPY_OK) { + * ... fail ... + * } + * char* output = (char*)malloc(output_length); + * if (snappy_uncompress(input, input_length, output, &output_length) + * == SNAPPY_OK) { + * ... Process(output, output_length) ... + * } + * free(output); + */ +snappy_status snappy_uncompress(const char* compressed, + size_t compressed_length, + char* uncompressed, + size_t* uncompressed_length); + +/* + * Returns the maximal size of the compressed representation of + * input data that is "source_length" bytes in length. + */ +size_t snappy_max_compressed_length(size_t source_length); + +/* + * REQUIRES: "compressed[]" was produced by snappy_compress() + * Returns SNAPPY_OK and stores the length of the uncompressed data in + * *result normally. Returns SNAPPY_INVALID_INPUT on parsing error. + * This operation takes O(1) time. + */ +snappy_status snappy_uncompressed_length(const char* compressed, + size_t compressed_length, + size_t* result); + +/* + * Check if the contents of "compressed[]" can be uncompressed successfully. + * Does not return the uncompressed data; if so, returns SNAPPY_OK, + * or if not, returns SNAPPY_INVALID_INPUT. + * Takes time proportional to compressed_length, but is usually at least a + * factor of four faster than actual decompression. + */ +snappy_status snappy_validate_compressed_buffer(const char* compressed, + size_t compressed_length); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* UTIL_SNAPPY_OPENSOURCE_SNAPPY_C_H_ */ diff --git a/ext/snappy/snappy-internal.h b/ext/snappy/snappy-internal.h new file mode 100644 index 0000000000..c99d33130b --- /dev/null +++ b/ext/snappy/snappy-internal.h @@ -0,0 +1,150 @@ +// Copyright 2008 Google Inc. All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Internals shared between the Snappy implementation and its unittest. + +#ifndef UTIL_SNAPPY_SNAPPY_INTERNAL_H_ +#define UTIL_SNAPPY_SNAPPY_INTERNAL_H_ + +#include "snappy-stubs-internal.h" + +namespace snappy { +namespace internal { + +class WorkingMemory { + public: + WorkingMemory() : large_table_(NULL) { } + ~WorkingMemory() { delete[] large_table_; } + + // Allocates and clears a hash table using memory in "*this", + // stores the number of buckets in "*table_size" and returns a pointer to + // the base of the hash table. + uint16* GetHashTable(size_t input_size, int* table_size); + + private: + uint16 small_table_[1<<10]; // 2KB + uint16* large_table_; // Allocated only when needed + + DISALLOW_COPY_AND_ASSIGN(WorkingMemory); +}; + +// Flat array compression that does not emit the "uncompressed length" +// prefix. Compresses "input" string to the "*op" buffer. +// +// REQUIRES: "input_length <= kBlockSize" +// REQUIRES: "op" points to an array of memory that is at least +// "MaxCompressedLength(input_length)" in size. +// REQUIRES: All elements in "table[0..table_size-1]" are initialized to zero. +// REQUIRES: "table_size" is a power of two +// +// Returns an "end" pointer into "op" buffer. +// "end - op" is the compressed size of "input". +char* CompressFragment(const char* input, + size_t input_length, + char* op, + uint16* table, + const int table_size); + +// Return the largest n such that +// +// s1[0,n-1] == s2[0,n-1] +// and n <= (s2_limit - s2). +// +// Does not read *s2_limit or beyond. +// Does not read *(s1 + (s2_limit - s2)) or beyond. +// Requires that s2_limit >= s2. +// +// Separate implementation for x86_64, for speed. Uses the fact that +// x86_64 is little endian. +#if defined(ARCH_K8) +static inline int FindMatchLength(const char* s1, + const char* s2, + const char* s2_limit) { + assert(s2_limit >= s2); + int matched = 0; + + // Find out how long the match is. We loop over the data 64 bits at a + // time until we find a 64-bit block that doesn't match; then we find + // the first non-matching bit and use that to calculate the total + // length of the match. + while (PREDICT_TRUE(s2 <= s2_limit - 8)) { + if (PREDICT_FALSE(UNALIGNED_LOAD64(s2) == UNALIGNED_LOAD64(s1 + matched))) { + s2 += 8; + matched += 8; + } else { + // On current (mid-2008) Opteron models there is a 3% more + // efficient code sequence to find the first non-matching byte. + // However, what follows is ~10% better on Intel Core 2 and newer, + // and we expect AMD's bsf instruction to improve. + uint64 x = UNALIGNED_LOAD64(s2) ^ UNALIGNED_LOAD64(s1 + matched); + int matching_bits = Bits::FindLSBSetNonZero64(x); + matched += matching_bits >> 3; + return matched; + } + } + while (PREDICT_TRUE(s2 < s2_limit)) { + if (PREDICT_TRUE(s1[matched] == *s2)) { + ++s2; + ++matched; + } else { + return matched; + } + } + return matched; +} +#else +static inline int FindMatchLength(const char* s1, + const char* s2, + const char* s2_limit) { + // Implementation based on the x86-64 version, above. + assert(s2_limit >= s2); + int matched = 0; + + while (s2 <= s2_limit - 4 && + UNALIGNED_LOAD32(s2) == UNALIGNED_LOAD32(s1 + matched)) { + s2 += 4; + matched += 4; + } + if (LittleEndian::IsLittleEndian() && s2 <= s2_limit - 4) { + uint32 x = UNALIGNED_LOAD32(s2) ^ UNALIGNED_LOAD32(s1 + matched); + int matching_bits = Bits::FindLSBSetNonZero(x); + matched += matching_bits >> 3; + } else { + while ((s2 < s2_limit) && (s1[matched] == *s2)) { + ++s2; + ++matched; + } + } + return matched; +} +#endif + +} // end namespace internal +} // end namespace snappy + +#endif // UTIL_SNAPPY_SNAPPY_INTERNAL_H_ diff --git a/ext/snappy/snappy-sinksource.h b/ext/snappy/snappy-sinksource.h new file mode 100644 index 0000000000..faabfa1e6f --- /dev/null +++ b/ext/snappy/snappy-sinksource.h @@ -0,0 +1,137 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef UTIL_SNAPPY_SNAPPY_SINKSOURCE_H_ +#define UTIL_SNAPPY_SNAPPY_SINKSOURCE_H_ + +#include + + +namespace snappy { + +// A Sink is an interface that consumes a sequence of bytes. +class Sink { + public: + Sink() { } + virtual ~Sink(); + + // Append "bytes[0,n-1]" to this. + virtual void Append(const char* bytes, size_t n) = 0; + + // Returns a writable buffer of the specified length for appending. + // May return a pointer to the caller-owned scratch buffer which + // must have at least the indicated length. The returned buffer is + // only valid until the next operation on this Sink. + // + // After writing at most "length" bytes, call Append() with the + // pointer returned from this function and the number of bytes + // written. Many Append() implementations will avoid copying + // bytes if this function returned an internal buffer. + // + // If a non-scratch buffer is returned, the caller may only pass a + // prefix of it to Append(). That is, it is not correct to pass an + // interior pointer of the returned array to Append(). + // + // The default implementation always returns the scratch buffer. + virtual char* GetAppendBuffer(size_t length, char* scratch); + + + private: + // No copying + Sink(const Sink&); + void operator=(const Sink&); +}; + +// A Source is an interface that yields a sequence of bytes +class Source { + public: + Source() { } + virtual ~Source(); + + // Return the number of bytes left to read from the source + virtual size_t Available() const = 0; + + // Peek at the next flat region of the source. Does not reposition + // the source. The returned region is empty iff Available()==0. + // + // Returns a pointer to the beginning of the region and store its + // length in *len. + // + // The returned region is valid until the next call to Skip() or + // until this object is destroyed, whichever occurs first. + // + // The returned region may be larger than Available() (for example + // if this ByteSource is a view on a substring of a larger source). + // The caller is responsible for ensuring that it only reads the + // Available() bytes. + virtual const char* Peek(size_t* len) = 0; + + // Skip the next n bytes. Invalidates any buffer returned by + // a previous call to Peek(). + // REQUIRES: Available() >= n + virtual void Skip(size_t n) = 0; + + private: + // No copying + Source(const Source&); + void operator=(const Source&); +}; + +// A Source implementation that yields the contents of a flat array +class ByteArraySource : public Source { + public: + ByteArraySource(const char* p, size_t n) : ptr_(p), left_(n) { } + virtual ~ByteArraySource(); + virtual size_t Available() const; + virtual const char* Peek(size_t* len); + virtual void Skip(size_t n); + private: + const char* ptr_; + size_t left_; +}; + +// A Sink implementation that writes to a flat array without any bound checks. +class UncheckedByteArraySink : public Sink { + public: + explicit UncheckedByteArraySink(char* dest) : dest_(dest) { } + virtual ~UncheckedByteArraySink(); + virtual void Append(const char* data, size_t n); + virtual char* GetAppendBuffer(size_t len, char* scratch); + + // Return the current output pointer so that a caller can see how + // many bytes were produced. + // Note: this is not a Sink method. + char* CurrentDestination() const { return dest_; } + private: + char* dest_; +}; + + +} + +#endif // UTIL_SNAPPY_SNAPPY_SINKSOURCE_H_ diff --git a/ext/snappy/snappy-stubs-internal.h b/ext/snappy/snappy-stubs-internal.h new file mode 100644 index 0000000000..12393b6289 --- /dev/null +++ b/ext/snappy/snappy-stubs-internal.h @@ -0,0 +1,491 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Various stubs for the open-source version of Snappy. + +#ifndef UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_ +#define UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include + +#ifdef HAVE_SYS_MMAN_H +#include +#endif + +#include "snappy-stubs-public.h" + +#if defined(__x86_64__) + +// Enable 64-bit optimized versions of some routines. +#define ARCH_K8 1 + +#endif + +// Needed by OS X, among others. +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + +// Pull in std::min, std::ostream, and the likes. This is safe because this +// header file is never used from any public header files. +using namespace std; + +// The size of an array, if known at compile-time. +// Will give unexpected results if used on a pointer. +// We undefine it first, since some compilers already have a definition. +#ifdef ARRAYSIZE +#undef ARRAYSIZE +#endif +#define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a))) + +// Static prediction hints. +#ifdef HAVE_BUILTIN_EXPECT +#define PREDICT_FALSE(x) (__builtin_expect(x, 0)) +#define PREDICT_TRUE(x) (__builtin_expect(!!(x), 1)) +#else +#define PREDICT_FALSE(x) x +#define PREDICT_TRUE(x) x +#endif + +// This is only used for recomputing the tag byte table used during +// decompression; for simplicity we just remove it from the open-source +// version (anyone who wants to regenerate it can just do the call +// themselves within main()). +#define DEFINE_bool(flag_name, default_value, description) \ + bool FLAGS_ ## flag_name = default_value +#define DECLARE_bool(flag_name) \ + extern bool FLAGS_ ## flag_name + +namespace snappy { + +static const uint32 kuint32max = static_cast(0xFFFFFFFF); +static const int64 kint64max = static_cast(0x7FFFFFFFFFFFFFFFLL); + +// Potentially unaligned loads and stores. + +// x86 and PowerPC can simply do these loads and stores native. + +#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) + +#define UNALIGNED_LOAD16(_p) (*reinterpret_cast(_p)) +#define UNALIGNED_LOAD32(_p) (*reinterpret_cast(_p)) +#define UNALIGNED_LOAD64(_p) (*reinterpret_cast(_p)) + +#define UNALIGNED_STORE16(_p, _val) (*reinterpret_cast(_p) = (_val)) +#define UNALIGNED_STORE32(_p, _val) (*reinterpret_cast(_p) = (_val)) +#define UNALIGNED_STORE64(_p, _val) (*reinterpret_cast(_p) = (_val)) + +// ARMv7 and newer support native unaligned accesses, but only of 16-bit +// and 32-bit values (not 64-bit); older versions either raise a fatal signal, +// do an unaligned read and rotate the words around a bit, or do the reads very +// slowly (trip through kernel mode). There's no simple #define that says just +// “ARMv7 or higher”, so we have to filter away all ARMv5 and ARMv6 +// sub-architectures. +// +// This is a mess, but there's not much we can do about it. + +#elif defined(__arm__) && \ + !defined(__ARM_ARCH_4__) && \ + !defined(__ARM_ARCH_4T__) && \ + !defined(__ARM_ARCH_5__) && \ + !defined(__ARM_ARCH_5T__) && \ + !defined(__ARM_ARCH_5TE__) && \ + !defined(__ARM_ARCH_5TEJ__) && \ + !defined(__ARM_ARCH_6__) && \ + !defined(__ARM_ARCH_6J__) && \ + !defined(__ARM_ARCH_6K__) && \ + !defined(__ARM_ARCH_6Z__) && \ + !defined(__ARM_ARCH_6ZK__) && \ + !defined(__ARM_ARCH_6T2__) + +#define UNALIGNED_LOAD16(_p) (*reinterpret_cast(_p)) +#define UNALIGNED_LOAD32(_p) (*reinterpret_cast(_p)) + +#define UNALIGNED_STORE16(_p, _val) (*reinterpret_cast(_p) = (_val)) +#define UNALIGNED_STORE32(_p, _val) (*reinterpret_cast(_p) = (_val)) + +// TODO(user): NEON supports unaligned 64-bit loads and stores. +// See if that would be more efficient on platforms supporting it, +// at least for copies. + +inline uint64 UNALIGNED_LOAD64(const void *p) { + uint64 t; + memcpy(&t, p, sizeof t); + return t; +} + +inline void UNALIGNED_STORE64(void *p, uint64 v) { + memcpy(p, &v, sizeof v); +} + +#else + +// These functions are provided for architectures that don't support +// unaligned loads and stores. + +inline uint16 UNALIGNED_LOAD16(const void *p) { + uint16 t; + memcpy(&t, p, sizeof t); + return t; +} + +inline uint32 UNALIGNED_LOAD32(const void *p) { + uint32 t; + memcpy(&t, p, sizeof t); + return t; +} + +inline uint64 UNALIGNED_LOAD64(const void *p) { + uint64 t; + memcpy(&t, p, sizeof t); + return t; +} + +inline void UNALIGNED_STORE16(void *p, uint16 v) { + memcpy(p, &v, sizeof v); +} + +inline void UNALIGNED_STORE32(void *p, uint32 v) { + memcpy(p, &v, sizeof v); +} + +inline void UNALIGNED_STORE64(void *p, uint64 v) { + memcpy(p, &v, sizeof v); +} + +#endif + +// This can be more efficient than UNALIGNED_LOAD64 + UNALIGNED_STORE64 +// on some platforms, in particular ARM. +inline void UnalignedCopy64(const void *src, void *dst) { + if (sizeof(void *) == 8) { + UNALIGNED_STORE64(dst, UNALIGNED_LOAD64(src)); + } else { + const char *src_char = reinterpret_cast(src); + char *dst_char = reinterpret_cast(dst); + + UNALIGNED_STORE32(dst_char, UNALIGNED_LOAD32(src_char)); + UNALIGNED_STORE32(dst_char + 4, UNALIGNED_LOAD32(src_char + 4)); + } +} + +// The following guarantees declaration of the byte swap functions. +#ifdef WORDS_BIGENDIAN + +#ifdef HAVE_SYS_BYTEORDER_H +#include +#endif + +#ifdef HAVE_SYS_ENDIAN_H +#include +#endif + +#ifdef _MSC_VER +#include +#define bswap_16(x) _byteswap_ushort(x) +#define bswap_32(x) _byteswap_ulong(x) +#define bswap_64(x) _byteswap_uint64(x) + +#elif defined(__APPLE__) +// Mac OS X / Darwin features +#include +#define bswap_16(x) OSSwapInt16(x) +#define bswap_32(x) OSSwapInt32(x) +#define bswap_64(x) OSSwapInt64(x) + +#elif defined(HAVE_BYTESWAP_H) +#include + +#elif defined(bswap32) +// FreeBSD defines bswap{16,32,64} in (already #included). +#define bswap_16(x) bswap16(x) +#define bswap_32(x) bswap32(x) +#define bswap_64(x) bswap64(x) + +#elif defined(BSWAP_64) +// Solaris 10 defines BSWAP_{16,32,64} in (already #included). +#define bswap_16(x) BSWAP_16(x) +#define bswap_32(x) BSWAP_32(x) +#define bswap_64(x) BSWAP_64(x) + +#else + +inline uint16 bswap_16(uint16 x) { + return (x << 8) | (x >> 8); +} + +inline uint32 bswap_32(uint32 x) { + x = ((x & 0xff00ff00UL) >> 8) | ((x & 0x00ff00ffUL) << 8); + return (x >> 16) | (x << 16); +} + +inline uint64 bswap_64(uint64 x) { + x = ((x & 0xff00ff00ff00ff00ULL) >> 8) | ((x & 0x00ff00ff00ff00ffULL) << 8); + x = ((x & 0xffff0000ffff0000ULL) >> 16) | ((x & 0x0000ffff0000ffffULL) << 16); + return (x >> 32) | (x << 32); +} + +#endif + +#endif // WORDS_BIGENDIAN + +// Convert to little-endian storage, opposite of network format. +// Convert x from host to little endian: x = LittleEndian.FromHost(x); +// convert x from little endian to host: x = LittleEndian.ToHost(x); +// +// Store values into unaligned memory converting to little endian order: +// LittleEndian.Store16(p, x); +// +// Load unaligned values stored in little endian converting to host order: +// x = LittleEndian.Load16(p); +class LittleEndian { + public: + // Conversion functions. +#ifdef WORDS_BIGENDIAN + + static uint16 FromHost16(uint16 x) { return bswap_16(x); } + static uint16 ToHost16(uint16 x) { return bswap_16(x); } + + static uint32 FromHost32(uint32 x) { return bswap_32(x); } + static uint32 ToHost32(uint32 x) { return bswap_32(x); } + + static bool IsLittleEndian() { return false; } + +#else // !defined(WORDS_BIGENDIAN) + + static uint16 FromHost16(uint16 x) { return x; } + static uint16 ToHost16(uint16 x) { return x; } + + static uint32 FromHost32(uint32 x) { return x; } + static uint32 ToHost32(uint32 x) { return x; } + + static bool IsLittleEndian() { return true; } + +#endif // !defined(WORDS_BIGENDIAN) + + // Functions to do unaligned loads and stores in little-endian order. + static uint16 Load16(const void *p) { + return ToHost16(UNALIGNED_LOAD16(p)); + } + + static void Store16(void *p, uint16 v) { + UNALIGNED_STORE16(p, FromHost16(v)); + } + + static uint32 Load32(const void *p) { + return ToHost32(UNALIGNED_LOAD32(p)); + } + + static void Store32(void *p, uint32 v) { + UNALIGNED_STORE32(p, FromHost32(v)); + } +}; + +// Some bit-manipulation functions. +class Bits { + public: + // Return floor(log2(n)) for positive integer n. Returns -1 iff n == 0. + static int Log2Floor(uint32 n); + + // Return the first set least / most significant bit, 0-indexed. Returns an + // undefined value if n == 0. FindLSBSetNonZero() is similar to ffs() except + // that it's 0-indexed. + static int FindLSBSetNonZero(uint32 n); + static int FindLSBSetNonZero64(uint64 n); + + private: + DISALLOW_COPY_AND_ASSIGN(Bits); +}; + +#ifdef HAVE_BUILTIN_CTZ + +inline int Bits::Log2Floor(uint32 n) { + return n == 0 ? -1 : 31 ^ __builtin_clz(n); +} + +inline int Bits::FindLSBSetNonZero(uint32 n) { + return __builtin_ctz(n); +} + +inline int Bits::FindLSBSetNonZero64(uint64 n) { + return __builtin_ctzll(n); +} + +#else // Portable versions. + +inline int Bits::Log2Floor(uint32 n) { + if (n == 0) + return -1; + int log = 0; + uint32 value = n; + for (int i = 4; i >= 0; --i) { + int shift = (1 << i); + uint32 x = value >> shift; + if (x != 0) { + value = x; + log += shift; + } + } + assert(value == 1); + return log; +} + +inline int Bits::FindLSBSetNonZero(uint32 n) { + int rc = 31; + for (int i = 4, shift = 1 << 4; i >= 0; --i) { + const uint32 x = n << shift; + if (x != 0) { + n = x; + rc -= shift; + } + shift >>= 1; + } + return rc; +} + +// FindLSBSetNonZero64() is defined in terms of FindLSBSetNonZero(). +inline int Bits::FindLSBSetNonZero64(uint64 n) { + const uint32 bottombits = static_cast(n); + if (bottombits == 0) { + // Bottom bits are zero, so scan in top bits + return 32 + FindLSBSetNonZero(static_cast(n >> 32)); + } else { + return FindLSBSetNonZero(bottombits); + } +} + +#endif // End portable versions. + +// Variable-length integer encoding. +class Varint { + public: + // Maximum lengths of varint encoding of uint32. + static const int kMax32 = 5; + + // Attempts to parse a varint32 from a prefix of the bytes in [ptr,limit-1]. + // Never reads a character at or beyond limit. If a valid/terminated varint32 + // was found in the range, stores it in *OUTPUT and returns a pointer just + // past the last byte of the varint32. Else returns NULL. On success, + // "result <= limit". + static const char* Parse32WithLimit(const char* ptr, const char* limit, + uint32* OUTPUT); + + // REQUIRES "ptr" points to a buffer of length sufficient to hold "v". + // EFFECTS Encodes "v" into "ptr" and returns a pointer to the + // byte just past the last encoded byte. + static char* Encode32(char* ptr, uint32 v); + + // EFFECTS Appends the varint representation of "value" to "*s". + static void Append32(string* s, uint32 value); +}; + +inline const char* Varint::Parse32WithLimit(const char* p, + const char* l, + uint32* OUTPUT) { + const unsigned char* ptr = reinterpret_cast(p); + const unsigned char* limit = reinterpret_cast(l); + uint32 b, result; + if (ptr >= limit) return NULL; + b = *(ptr++); result = b & 127; if (b < 128) goto done; + if (ptr >= limit) return NULL; + b = *(ptr++); result |= (b & 127) << 7; if (b < 128) goto done; + if (ptr >= limit) return NULL; + b = *(ptr++); result |= (b & 127) << 14; if (b < 128) goto done; + if (ptr >= limit) return NULL; + b = *(ptr++); result |= (b & 127) << 21; if (b < 128) goto done; + if (ptr >= limit) return NULL; + b = *(ptr++); result |= (b & 127) << 28; if (b < 16) goto done; + return NULL; // Value is too long to be a varint32 + done: + *OUTPUT = result; + return reinterpret_cast(ptr); +} + +inline char* Varint::Encode32(char* sptr, uint32 v) { + // Operate on characters as unsigneds + unsigned char* ptr = reinterpret_cast(sptr); + static const int B = 128; + if (v < (1<<7)) { + *(ptr++) = v; + } else if (v < (1<<14)) { + *(ptr++) = v | B; + *(ptr++) = v>>7; + } else if (v < (1<<21)) { + *(ptr++) = v | B; + *(ptr++) = (v>>7) | B; + *(ptr++) = v>>14; + } else if (v < (1<<28)) { + *(ptr++) = v | B; + *(ptr++) = (v>>7) | B; + *(ptr++) = (v>>14) | B; + *(ptr++) = v>>21; + } else { + *(ptr++) = v | B; + *(ptr++) = (v>>7) | B; + *(ptr++) = (v>>14) | B; + *(ptr++) = (v>>21) | B; + *(ptr++) = v>>28; + } + return reinterpret_cast(ptr); +} + +// If you know the internal layout of the std::string in use, you can +// replace this function with one that resizes the string without +// filling the new space with zeros (if applicable) -- +// it will be non-portable but faster. +inline void STLStringResizeUninitialized(string* s, size_t new_size) { + s->resize(new_size); +} + +// Return a mutable char* pointing to a string's internal buffer, +// which may not be null-terminated. Writing through this pointer will +// modify the string. +// +// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the +// next call to a string method that invalidates iterators. +// +// As of 2006-04, there is no standard-blessed way of getting a +// mutable reference to a string's internal buffer. However, issue 530 +// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-defects.html#530) +// proposes this as the method. It will officially be part of the standard +// for C++0x. This should already work on all current implementations. +inline char* string_as_array(string* str) { + return str->empty() ? NULL : &*str->begin(); +} + +} // namespace snappy + +#endif // UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_ diff --git a/ext/snappy/snappy-stubs-public.h b/ext/snappy/snappy-stubs-public.h new file mode 100644 index 0000000000..e97fc24682 --- /dev/null +++ b/ext/snappy/snappy-stubs-public.h @@ -0,0 +1,61 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// Author: sesse@google.com (Steinar H. Gunderson) +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Various type stubs for the open-source version of Snappy. +// +// This file cannot include config.h, as it is included from snappy.h, +// which is a public header. Instead, snappy-stubs-public.h is generated by +// from snappy-stubs-public.h.in at configure time. + +#ifndef UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_ +#define UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_ + +#include "base/basictypes.h" +#include + +namespace snappy { + +typedef int8_t int8; +typedef uint8_t uint8; +typedef int16_t int16; +typedef uint16_t uint16; +typedef int32_t int32; +typedef uint32_t uint32; +typedef int64_t int64; +typedef uint64_t uint64; + +typedef std::string string; + +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +} // namespace snappy + +#endif // UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_ diff --git a/ext/snappy/snappy.cpp b/ext/snappy/snappy.cpp new file mode 100644 index 0000000000..26ef022cca --- /dev/null +++ b/ext/snappy/snappy.cpp @@ -0,0 +1,1166 @@ +// Copyright 2005 Google Inc. All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "snappy.h" +#include "snappy-internal.h" +#include "snappy-sinksource.h" + +#include + +#include +#include +#include + + +namespace snappy { + + Source::~Source() { } + + Sink::~Sink() { } + + char* Sink::GetAppendBuffer(size_t length, char* scratch) { + return scratch; + } + + ByteArraySource::~ByteArraySource() { } + + size_t ByteArraySource::Available() const { return left_; } + + const char* ByteArraySource::Peek(size_t* len) { + *len = left_; + return ptr_; + } + + void ByteArraySource::Skip(size_t n) { + left_ -= n; + ptr_ += n; + } + + UncheckedByteArraySink::~UncheckedByteArraySink() { } + + void UncheckedByteArraySink::Append(const char* data, size_t n) { + // Do no copying if the caller filled in the result of GetAppendBuffer() + if (data != dest_) { + memcpy(dest_, data, n); + } + dest_ += n; + } + + char* UncheckedByteArraySink::GetAppendBuffer(size_t len, char* scratch) { + return dest_; + } + +} + + +namespace snappy { + +// Any hash function will produce a valid compressed bitstream, but a good +// hash function reduces the number of collisions and thus yields better +// compression for compressible input, and more speed for incompressible +// input. Of course, it doesn't hurt if the hash function is reasonably fast +// either, as it gets called a lot. +static inline uint32 HashBytes(uint32 bytes, int shift) { + uint32 kMul = 0x1e35a7bd; + return (bytes * kMul) >> shift; +} +static inline uint32 Hash(const char* p, int shift) { + return HashBytes(UNALIGNED_LOAD32(p), shift); +} + +size_t MaxCompressedLength(size_t source_len) { + // Compressed data can be defined as: + // compressed := item* literal* + // item := literal* copy + // + // The trailing literal sequence has a space blowup of at most 62/60 + // since a literal of length 60 needs one tag byte + one extra byte + // for length information. + // + // Item blowup is trickier to measure. Suppose the "copy" op copies + // 4 bytes of data. Because of a special check in the encoding code, + // we produce a 4-byte copy only if the offset is < 65536. Therefore + // the copy op takes 3 bytes to encode, and this type of item leads + // to at most the 62/60 blowup for representing literals. + // + // Suppose the "copy" op copies 5 bytes of data. If the offset is big + // enough, it will take 5 bytes to encode the copy op. Therefore the + // worst case here is a one-byte literal followed by a five-byte copy. + // I.e., 6 bytes of input turn into 7 bytes of "compressed" data. + // + // This last factor dominates the blowup, so the final estimate is: + return 32 + source_len + source_len/6; +} + +enum { + LITERAL = 0, + COPY_1_BYTE_OFFSET = 1, // 3 bit length + 3 bits of offset in opcode + COPY_2_BYTE_OFFSET = 2, + COPY_4_BYTE_OFFSET = 3 +}; + +void Varint::Append32(string* s, uint32 value) { + char buf[Varint::kMax32]; + const char* p = Varint::Encode32(buf, value); + s->append(buf, p - buf); +} + +// Copy "len" bytes from "src" to "op", one byte at a time. Used for +// handling COPY operations where the input and output regions may +// overlap. For example, suppose: +// src == "ab" +// op == src + 2 +// len == 20 +// After IncrementalCopy(src, op, len), the result will have +// eleven copies of "ab" +// ababababababababababab +// Note that this does not match the semantics of either memcpy() +// or memmove(). +static inline void IncrementalCopy(const char* src, char* op, int len) { + assert(len > 0); + do { + *op++ = *src++; + } while (--len > 0); +} + +// Equivalent to IncrementalCopy except that it can write up to ten extra +// bytes after the end of the copy, and that it is faster. +// +// The main part of this loop is a simple copy of eight bytes at a time until +// we've copied (at least) the requested amount of bytes. However, if op and +// src are less than eight bytes apart (indicating a repeating pattern of +// length < 8), we first need to expand the pattern in order to get the correct +// results. For instance, if the buffer looks like this, with the eight-byte +// and patterns marked as intervals: +// +// abxxxxxxxxxxxx +// [------] src +// [------] op +// +// a single eight-byte copy from to will repeat the pattern once, +// after which we can move two bytes without moving : +// +// ababxxxxxxxxxx +// [------] src +// [------] op +// +// and repeat the exercise until the two no longer overlap. +// +// This allows us to do very well in the special case of one single byte +// repeated many times, without taking a big hit for more general cases. +// +// The worst case of extra writing past the end of the match occurs when +// op - src == 1 and len == 1; the last copy will read from byte positions +// [0..7] and write to [4..11], whereas it was only supposed to write to +// position 1. Thus, ten excess bytes. + +namespace { + +const int kMaxIncrementCopyOverflow = 10; + +} // namespace + +static inline void IncrementalCopyFastPath(const char* src, char* op, int len) { + while (op - src < 8) { + UnalignedCopy64(src, op); + len -= op - src; + op += op - src; + } + while (len > 0) { + UnalignedCopy64(src, op); + src += 8; + op += 8; + len -= 8; + } +} + +static inline char* EmitLiteral(char* op, + const char* literal, + int len, + bool allow_fast_path) { + int n = len - 1; // Zero-length literals are disallowed + if (n < 60) { + // Fits in tag byte + *op++ = LITERAL | (n << 2); + + // The vast majority of copies are below 16 bytes, for which a + // call to memcpy is overkill. This fast path can sometimes + // copy up to 15 bytes too much, but that is okay in the + // main loop, since we have a bit to go on for both sides: + // + // - The input will always have kInputMarginBytes = 15 extra + // available bytes, as long as we're in the main loop, and + // if not, allow_fast_path = false. + // - The output will always have 32 spare bytes (see + // MaxCompressedLength). + if (allow_fast_path && len <= 16) { + UnalignedCopy64(literal, op); + UnalignedCopy64(literal + 8, op + 8); + return op + len; + } + } else { + // Encode in upcoming bytes + char* base = op; + int count = 0; + op++; + while (n > 0) { + *op++ = n & 0xff; + n >>= 8; + count++; + } + assert(count >= 1); + assert(count <= 4); + *base = LITERAL | ((59+count) << 2); + } + memcpy(op, literal, len); + return op + len; +} + +static inline char* EmitCopyLessThan64(char* op, size_t offset, int len) { + assert(len <= 64); + assert(len >= 4); + assert(offset < 65536); + + if ((len < 12) && (offset < 2048)) { + size_t len_minus_4 = len - 4; + assert(len_minus_4 < 8); // Must fit in 3 bits + *op++ = COPY_1_BYTE_OFFSET | ((len_minus_4) << 2) | ((offset >> 8) << 5); + *op++ = offset & 0xff; + } else { + *op++ = COPY_2_BYTE_OFFSET | ((len-1) << 2); + LittleEndian::Store16(op, offset); + op += 2; + } + return op; +} + +static inline char* EmitCopy(char* op, size_t offset, int len) { + // Emit 64 byte copies but make sure to keep at least four bytes reserved + while (len >= 68) { + op = EmitCopyLessThan64(op, offset, 64); + len -= 64; + } + + // Emit an extra 60 byte copy if have too much data to fit in one copy + if (len > 64) { + op = EmitCopyLessThan64(op, offset, 60); + len -= 60; + } + + // Emit remainder + op = EmitCopyLessThan64(op, offset, len); + return op; +} + + +bool GetUncompressedLength(const char* start, size_t n, size_t* result) { + uint32 v = 0; + const char* limit = start + n; + if (Varint::Parse32WithLimit(start, limit, &v) != NULL) { + *result = v; + return true; + } else { + return false; + } +} + +namespace internal { +uint16* WorkingMemory::GetHashTable(size_t input_size, int* table_size) { + // Use smaller hash table when input.size() is smaller, since we + // fill the table, incurring O(hash table size) overhead for + // compression, and if the input is short, we won't need that + // many hash table entries anyway. + assert(kMaxHashTableSize >= 256); + size_t htsize = 256; + while (htsize < kMaxHashTableSize && htsize < input_size) { + htsize <<= 1; + } + + uint16* table; + if (htsize <= ARRAYSIZE(small_table_)) { + table = small_table_; + } else { + if (large_table_ == NULL) { + large_table_ = new uint16[kMaxHashTableSize]; + } + table = large_table_; + } + + *table_size = htsize; + memset(table, 0, htsize * sizeof(*table)); + return table; +} +} // end namespace internal + +// For 0 <= offset <= 4, GetUint32AtOffset(GetEightBytesAt(p), offset) will +// equal UNALIGNED_LOAD32(p + offset). Motivation: On x86-64 hardware we have +// empirically found that overlapping loads such as +// UNALIGNED_LOAD32(p) ... UNALIGNED_LOAD32(p+1) ... UNALIGNED_LOAD32(p+2) +// are slower than UNALIGNED_LOAD64(p) followed by shifts and casts to uint32. +// +// We have different versions for 64- and 32-bit; ideally we would avoid the +// two functions and just inline the UNALIGNED_LOAD64 call into +// GetUint32AtOffset, but GCC (at least not as of 4.6) is seemingly not clever +// enough to avoid loading the value multiple times then. For 64-bit, the load +// is done when GetEightBytesAt() is called, whereas for 32-bit, the load is +// done at GetUint32AtOffset() time. + +#ifdef ARCH_K8 + +typedef uint64 EightBytesReference; + +static inline EightBytesReference GetEightBytesAt(const char* ptr) { + return UNALIGNED_LOAD64(ptr); +} + +static inline uint32 GetUint32AtOffset(uint64 v, int offset) { + assert(offset >= 0); + assert(offset <= 4); + return v >> (LittleEndian::IsLittleEndian() ? 8 * offset : 32 - 8 * offset); +} + +#else + +typedef const char* EightBytesReference; + +static inline EightBytesReference GetEightBytesAt(const char* ptr) { + return ptr; +} + +static inline uint32 GetUint32AtOffset(const char* v, int offset) { + assert(offset >= 0); + assert(offset <= 4); + return UNALIGNED_LOAD32(v + offset); +} + +#endif + +// Flat array compression that does not emit the "uncompressed length" +// prefix. Compresses "input" string to the "*op" buffer. +// +// REQUIRES: "input" is at most "kBlockSize" bytes long. +// REQUIRES: "op" points to an array of memory that is at least +// "MaxCompressedLength(input.size())" in size. +// REQUIRES: All elements in "table[0..table_size-1]" are initialized to zero. +// REQUIRES: "table_size" is a power of two +// +// Returns an "end" pointer into "op" buffer. +// "end - op" is the compressed size of "input". +namespace internal { +char* CompressFragment(const char* input, + size_t input_size, + char* op, + uint16* table, + const int table_size) { + // "ip" is the input pointer, and "op" is the output pointer. + const char* ip = input; + assert(input_size <= kBlockSize); + assert((table_size & (table_size - 1)) == 0); // table must be power of two + const int shift = 32 - Bits::Log2Floor(table_size); + assert(static_cast(kuint32max >> shift) == table_size - 1); + const char* ip_end = input + input_size; + const char* base_ip = ip; + // Bytes in [next_emit, ip) will be emitted as literal bytes. Or + // [next_emit, ip_end) after the main loop. + const char* next_emit = ip; + + const size_t kInputMarginBytes = 15; + if (PREDICT_TRUE(input_size >= kInputMarginBytes)) { + const char* ip_limit = input + input_size - kInputMarginBytes; + + for (uint32 next_hash = Hash(++ip, shift); ; ) { + assert(next_emit < ip); + // The body of this loop calls EmitLiteral once and then EmitCopy one or + // more times. (The exception is that when we're close to exhausting + // the input we goto emit_remainder.) + // + // In the first iteration of this loop we're just starting, so + // there's nothing to copy, so calling EmitLiteral once is + // necessary. And we only start a new iteration when the + // current iteration has determined that a call to EmitLiteral will + // precede the next call to EmitCopy (if any). + // + // Step 1: Scan forward in the input looking for a 4-byte-long match. + // If we get close to exhausting the input then goto emit_remainder. + // + // Heuristic match skipping: If 32 bytes are scanned with no matches + // found, start looking only at every other byte. If 32 more bytes are + // scanned, look at every third byte, etc.. When a match is found, + // immediately go back to looking at every byte. This is a small loss + // (~5% performance, ~0.1% density) for compressible data due to more + // bookkeeping, but for non-compressible data (such as JPEG) it's a huge + // win since the compressor quickly "realizes" the data is incompressible + // and doesn't bother looking for matches everywhere. + // + // The "skip" variable keeps track of how many bytes there are since the + // last match; dividing it by 32 (ie. right-shifting by five) gives the + // number of bytes to move ahead for each iteration. + uint32 skip = 32; + + const char* next_ip = ip; + const char* candidate; + do { + ip = next_ip; + uint32 hash = next_hash; + assert(hash == Hash(ip, shift)); + uint32 bytes_between_hash_lookups = skip++ >> 5; + next_ip = ip + bytes_between_hash_lookups; + if (PREDICT_FALSE(next_ip > ip_limit)) { + goto emit_remainder; + } + next_hash = Hash(next_ip, shift); + candidate = base_ip + table[hash]; + assert(candidate >= base_ip); + assert(candidate < ip); + + table[hash] = ip - base_ip; + } while (PREDICT_TRUE(UNALIGNED_LOAD32(ip) != + UNALIGNED_LOAD32(candidate))); + + // Step 2: A 4-byte match has been found. We'll later see if more + // than 4 bytes match. But, prior to the match, input + // bytes [next_emit, ip) are unmatched. Emit them as "literal bytes." + assert(next_emit + 16 <= ip_end); + op = EmitLiteral(op, next_emit, ip - next_emit, true); + + // Step 3: Call EmitCopy, and then see if another EmitCopy could + // be our next move. Repeat until we find no match for the + // input immediately after what was consumed by the last EmitCopy call. + // + // If we exit this loop normally then we need to call EmitLiteral next, + // though we don't yet know how big the literal will be. We handle that + // by proceeding to the next iteration of the main loop. We also can exit + // this loop via goto if we get close to exhausting the input. + EightBytesReference input_bytes; + uint32 candidate_bytes = 0; + + do { + // We have a 4-byte match at ip, and no need to emit any + // "literal bytes" prior to ip. + const char* base = ip; + int matched = 4 + FindMatchLength(candidate + 4, ip + 4, ip_end); + ip += matched; + size_t offset = base - candidate; + assert(0 == memcmp(base, candidate, matched)); + op = EmitCopy(op, offset, matched); + // We could immediately start working at ip now, but to improve + // compression we first update table[Hash(ip - 1, ...)]. + const char* insert_tail = ip - 1; + next_emit = ip; + if (PREDICT_FALSE(ip >= ip_limit)) { + goto emit_remainder; + } + input_bytes = GetEightBytesAt(insert_tail); + uint32 prev_hash = HashBytes(GetUint32AtOffset(input_bytes, 0), shift); + table[prev_hash] = ip - base_ip - 1; + uint32 cur_hash = HashBytes(GetUint32AtOffset(input_bytes, 1), shift); + candidate = base_ip + table[cur_hash]; + candidate_bytes = UNALIGNED_LOAD32(candidate); + table[cur_hash] = ip - base_ip; + } while (GetUint32AtOffset(input_bytes, 1) == candidate_bytes); + + next_hash = HashBytes(GetUint32AtOffset(input_bytes, 2), shift); + ++ip; + } + } + + emit_remainder: + // Emit the remaining bytes as a literal + if (next_emit < ip_end) { + op = EmitLiteral(op, next_emit, ip_end - next_emit, false); + } + + return op; +} +} // end namespace internal + +// Signature of output types needed by decompression code. +// The decompression code is templatized on a type that obeys this +// signature so that we do not pay virtual function call overhead in +// the middle of a tight decompression loop. +// +// class DecompressionWriter { +// public: +// // Called before decompression +// void SetExpectedLength(size_t length); +// +// // Called after decompression +// bool CheckLength() const; +// +// // Called repeatedly during decompression +// bool Append(const char* ip, size_t length); +// bool AppendFromSelf(uint32 offset, size_t length); +// +// // The difference between TryFastAppend and Append is that TryFastAppend +// // is allowed to read up to bytes from the input buffer, +// // whereas Append is allowed to read . +// // +// // Also, TryFastAppend is allowed to return false, declining the append, +// // without it being a fatal error -- just "return false" would be +// // a perfectly legal implementation of TryFastAppend. The intention +// // is for TryFastAppend to allow a fast path in the common case of +// // a small append. +// // +// // NOTE(user): TryFastAppend must always return decline (return false) +// // if is 61 or more, as in this case the literal length is not +// // decoded fully. In practice, this should not be a big problem, +// // as it is unlikely that one would implement a fast path accepting +// // this much data. +// bool TryFastAppend(const char* ip, size_t available, size_t length); +// }; + +// ----------------------------------------------------------------------- +// Lookup table for decompression code. Generated by ComputeTable() below. +// ----------------------------------------------------------------------- + +// Mapping from i in range [0,4] to a mask to extract the bottom 8*i bits +static const uint32 wordmask[] = { + 0u, 0xffu, 0xffffu, 0xffffffu, 0xffffffffu +}; + +// Data stored per entry in lookup table: +// Range Bits-used Description +// ------------------------------------ +// 1..64 0..7 Literal/copy length encoded in opcode byte +// 0..7 8..10 Copy offset encoded in opcode byte / 256 +// 0..4 11..13 Extra bytes after opcode +// +// We use eight bits for the length even though 7 would have sufficed +// because of efficiency reasons: +// (1) Extracting a byte is faster than a bit-field +// (2) It properly aligns copy offset so we do not need a <<8 +static const uint16 char_table[256] = { + 0x0001, 0x0804, 0x1001, 0x2001, 0x0002, 0x0805, 0x1002, 0x2002, + 0x0003, 0x0806, 0x1003, 0x2003, 0x0004, 0x0807, 0x1004, 0x2004, + 0x0005, 0x0808, 0x1005, 0x2005, 0x0006, 0x0809, 0x1006, 0x2006, + 0x0007, 0x080a, 0x1007, 0x2007, 0x0008, 0x080b, 0x1008, 0x2008, + 0x0009, 0x0904, 0x1009, 0x2009, 0x000a, 0x0905, 0x100a, 0x200a, + 0x000b, 0x0906, 0x100b, 0x200b, 0x000c, 0x0907, 0x100c, 0x200c, + 0x000d, 0x0908, 0x100d, 0x200d, 0x000e, 0x0909, 0x100e, 0x200e, + 0x000f, 0x090a, 0x100f, 0x200f, 0x0010, 0x090b, 0x1010, 0x2010, + 0x0011, 0x0a04, 0x1011, 0x2011, 0x0012, 0x0a05, 0x1012, 0x2012, + 0x0013, 0x0a06, 0x1013, 0x2013, 0x0014, 0x0a07, 0x1014, 0x2014, + 0x0015, 0x0a08, 0x1015, 0x2015, 0x0016, 0x0a09, 0x1016, 0x2016, + 0x0017, 0x0a0a, 0x1017, 0x2017, 0x0018, 0x0a0b, 0x1018, 0x2018, + 0x0019, 0x0b04, 0x1019, 0x2019, 0x001a, 0x0b05, 0x101a, 0x201a, + 0x001b, 0x0b06, 0x101b, 0x201b, 0x001c, 0x0b07, 0x101c, 0x201c, + 0x001d, 0x0b08, 0x101d, 0x201d, 0x001e, 0x0b09, 0x101e, 0x201e, + 0x001f, 0x0b0a, 0x101f, 0x201f, 0x0020, 0x0b0b, 0x1020, 0x2020, + 0x0021, 0x0c04, 0x1021, 0x2021, 0x0022, 0x0c05, 0x1022, 0x2022, + 0x0023, 0x0c06, 0x1023, 0x2023, 0x0024, 0x0c07, 0x1024, 0x2024, + 0x0025, 0x0c08, 0x1025, 0x2025, 0x0026, 0x0c09, 0x1026, 0x2026, + 0x0027, 0x0c0a, 0x1027, 0x2027, 0x0028, 0x0c0b, 0x1028, 0x2028, + 0x0029, 0x0d04, 0x1029, 0x2029, 0x002a, 0x0d05, 0x102a, 0x202a, + 0x002b, 0x0d06, 0x102b, 0x202b, 0x002c, 0x0d07, 0x102c, 0x202c, + 0x002d, 0x0d08, 0x102d, 0x202d, 0x002e, 0x0d09, 0x102e, 0x202e, + 0x002f, 0x0d0a, 0x102f, 0x202f, 0x0030, 0x0d0b, 0x1030, 0x2030, + 0x0031, 0x0e04, 0x1031, 0x2031, 0x0032, 0x0e05, 0x1032, 0x2032, + 0x0033, 0x0e06, 0x1033, 0x2033, 0x0034, 0x0e07, 0x1034, 0x2034, + 0x0035, 0x0e08, 0x1035, 0x2035, 0x0036, 0x0e09, 0x1036, 0x2036, + 0x0037, 0x0e0a, 0x1037, 0x2037, 0x0038, 0x0e0b, 0x1038, 0x2038, + 0x0039, 0x0f04, 0x1039, 0x2039, 0x003a, 0x0f05, 0x103a, 0x203a, + 0x003b, 0x0f06, 0x103b, 0x203b, 0x003c, 0x0f07, 0x103c, 0x203c, + 0x0801, 0x0f08, 0x103d, 0x203d, 0x1001, 0x0f09, 0x103e, 0x203e, + 0x1801, 0x0f0a, 0x103f, 0x203f, 0x2001, 0x0f0b, 0x1040, 0x2040 +}; + +// In debug mode, allow optional computation of the table at startup. +// Also, check that the decompression table is correct. +#ifndef NDEBUG +DEFINE_bool(snappy_dump_decompression_table, false, + "If true, we print the decompression table at startup."); + +static uint16 MakeEntry(unsigned int extra, + unsigned int len, + unsigned int copy_offset) { + // Check that all of the fields fit within the allocated space + assert(extra == (extra & 0x7)); // At most 3 bits + assert(copy_offset == (copy_offset & 0x7)); // At most 3 bits + assert(len == (len & 0x7f)); // At most 7 bits + return len | (copy_offset << 8) | (extra << 11); +} + +static void ComputeTable() { + uint16 dst[256]; + + // Place invalid entries in all places to detect missing initialization + int assigned = 0; + for (int i = 0; i < 256; i++) { + dst[i] = 0xffff; + } + + // Small LITERAL entries. We store (len-1) in the top 6 bits. + for (unsigned int len = 1; len <= 60; len++) { + dst[LITERAL | ((len-1) << 2)] = MakeEntry(0, len, 0); + assigned++; + } + + // Large LITERAL entries. We use 60..63 in the high 6 bits to + // encode the number of bytes of length info that follow the opcode. + for (unsigned int extra_bytes = 1; extra_bytes <= 4; extra_bytes++) { + // We set the length field in the lookup table to 1 because extra + // bytes encode len-1. + dst[LITERAL | ((extra_bytes+59) << 2)] = MakeEntry(extra_bytes, 1, 0); + assigned++; + } + + // COPY_1_BYTE_OFFSET. + // + // The tag byte in the compressed data stores len-4 in 3 bits, and + // offset/256 in 5 bits. offset%256 is stored in the next byte. + // + // This format is used for length in range [4..11] and offset in + // range [0..2047] + for (unsigned int len = 4; len < 12; len++) { + for (unsigned int offset = 0; offset < 2048; offset += 256) { + dst[COPY_1_BYTE_OFFSET | ((len-4)<<2) | ((offset>>8)<<5)] = + MakeEntry(1, len, offset>>8); + assigned++; + } + } + + // COPY_2_BYTE_OFFSET. + // Tag contains len-1 in top 6 bits, and offset in next two bytes. + for (unsigned int len = 1; len <= 64; len++) { + dst[COPY_2_BYTE_OFFSET | ((len-1)<<2)] = MakeEntry(2, len, 0); + assigned++; + } + + // COPY_4_BYTE_OFFSET. + // Tag contents len-1 in top 6 bits, and offset in next four bytes. + for (unsigned int len = 1; len <= 64; len++) { + dst[COPY_4_BYTE_OFFSET | ((len-1)<<2)] = MakeEntry(4, len, 0); + assigned++; + } + + // Check that each entry was initialized exactly once. + if (assigned != 256) { + fprintf(stderr, "ComputeTable: assigned only %d of 256\n", assigned); + abort(); + } + for (int i = 0; i < 256; i++) { + if (dst[i] == 0xffff) { + fprintf(stderr, "ComputeTable: did not assign byte %d\n", i); + abort(); + } + } + + if (FLAGS_snappy_dump_decompression_table) { + printf("static const uint16 char_table[256] = {\n "); + for (int i = 0; i < 256; i++) { + printf("0x%04x%s", + dst[i], + ((i == 255) ? "\n" : (((i%8) == 7) ? ",\n " : ", "))); + } + printf("};\n"); + } + + // Check that computed table matched recorded table + for (int i = 0; i < 256; i++) { + if (dst[i] != char_table[i]) { + fprintf(stderr, "ComputeTable: byte %d: computed (%x), expect (%x)\n", + i, static_cast(dst[i]), static_cast(char_table[i])); + abort(); + } + } +} +#endif /* !NDEBUG */ + +// Helper class for decompression +class SnappyDecompressor { + private: + Source* reader_; // Underlying source of bytes to decompress + const char* ip_; // Points to next buffered byte + const char* ip_limit_; // Points just past buffered bytes + uint32 peeked_; // Bytes peeked from reader (need to skip) + bool eof_; // Hit end of input without an error? + char scratch_[5]; // Temporary buffer for PeekFast() boundaries + + // Ensure that all of the tag metadata for the next tag is available + // in [ip_..ip_limit_-1]. Also ensures that [ip,ip+4] is readable even + // if (ip_limit_ - ip_ < 5). + // + // Returns true on success, false on error or end of input. + bool RefillTag(); + + public: + explicit SnappyDecompressor(Source* reader) + : reader_(reader), + ip_(NULL), + ip_limit_(NULL), + peeked_(0), + eof_(false) { + } + + ~SnappyDecompressor() { + // Advance past any bytes we peeked at from the reader + reader_->Skip(peeked_); + } + + // Returns true iff we have hit the end of the input without an error. + bool eof() const { + return eof_; + } + + // Read the uncompressed length stored at the start of the compressed data. + // On succcess, stores the length in *result and returns true. + // On failure, returns false. + bool ReadUncompressedLength(uint32* result) { + assert(ip_ == NULL); // Must not have read anything yet + // Length is encoded in 1..5 bytes + *result = 0; + uint32 shift = 0; + while (true) { + if (shift >= 32) return false; + size_t n; + const char* ip = reader_->Peek(&n); + if (n == 0) return false; + const unsigned char c = *(reinterpret_cast(ip)); + reader_->Skip(1); + *result |= static_cast(c & 0x7f) << shift; + if (c < 128) { + break; + } + shift += 7; + } + return true; + } + + // Process the next item found in the input. + // Returns true if successful, false on error or end of input. + template + void DecompressAllTags(Writer* writer) { + const char* ip = ip_; + + // We could have put this refill fragment only at the beginning of the loop. + // However, duplicating it at the end of each branch gives the compiler more + // scope to optimize the expression based on the local + // context, which overall increases speed. + #define MAYBE_REFILL() \ + if (ip_limit_ - ip < 5) { \ + ip_ = ip; \ + if (!RefillTag()) return; \ + ip = ip_; \ + } + + MAYBE_REFILL(); + for ( ;; ) { + const unsigned char c = *(reinterpret_cast(ip++)); + + if ((c & 0x3) == LITERAL) { + size_t literal_length = (c >> 2) + 1u; + if (writer->TryFastAppend(ip, ip_limit_ - ip, literal_length)) { + assert(literal_length < 61); + ip += literal_length; + MAYBE_REFILL(); + continue; + } + if (PREDICT_FALSE(literal_length >= 61)) { + // Long literal. + const size_t literal_length_length = literal_length - 60; + literal_length = + (LittleEndian::Load32(ip) & wordmask[literal_length_length]) + 1; + ip += literal_length_length; + } + + size_t avail = ip_limit_ - ip; + while (avail < literal_length) { + if (!writer->Append(ip, avail)) return; + literal_length -= avail; + reader_->Skip(peeked_); + size_t n; + ip = reader_->Peek(&n); + avail = n; + peeked_ = avail; + if (avail == 0) return; // Premature end of input + ip_limit_ = ip + avail; + } + if (!writer->Append(ip, literal_length)) { + return; + } + ip += literal_length; + MAYBE_REFILL(); + } else { + const uint32 entry = char_table[c]; + const uint32 trailer = LittleEndian::Load32(ip) & wordmask[entry >> 11]; + const uint32 length = entry & 0xff; + ip += entry >> 11; + + // copy_offset/256 is encoded in bits 8..10. By just fetching + // those bits, we get copy_offset (since the bit-field starts at + // bit 8). + const uint32 copy_offset = entry & 0x700; + if (!writer->AppendFromSelf(copy_offset + trailer, length)) { + return; + } + MAYBE_REFILL(); + } + } + +#undef MAYBE_REFILL + } +}; + +bool SnappyDecompressor::RefillTag() { + const char* ip = ip_; + if (ip == ip_limit_) { + // Fetch a new fragment from the reader + reader_->Skip(peeked_); // All peeked bytes are used up + size_t n; + ip = reader_->Peek(&n); + peeked_ = n; + if (n == 0) { + eof_ = true; + return false; + } + ip_limit_ = ip + n; + } + + // Read the tag character + assert(ip < ip_limit_); + const unsigned char c = *(reinterpret_cast(ip)); + const uint32 entry = char_table[c]; + const uint32 needed = (entry >> 11) + 1; // +1 byte for 'c' + assert(needed <= sizeof(scratch_)); + + // Read more bytes from reader if needed + uint32 nbuf = ip_limit_ - ip; + if (nbuf < needed) { + // Stitch together bytes from ip and reader to form the word + // contents. We store the needed bytes in "scratch_". They + // will be consumed immediately by the caller since we do not + // read more than we need. + memmove(scratch_, ip, nbuf); + reader_->Skip(peeked_); // All peeked bytes are used up + peeked_ = 0; + while (nbuf < needed) { + size_t length; + const char* src = reader_->Peek(&length); + if (length == 0) return false; + uint32 to_add = min(needed - nbuf, length); + memcpy(scratch_ + nbuf, src, to_add); + nbuf += to_add; + reader_->Skip(to_add); + } + assert(nbuf == needed); + ip_ = scratch_; + ip_limit_ = scratch_ + needed; + } else if (nbuf < 5) { + // Have enough bytes, but move into scratch_ so that we do not + // read past end of input + memmove(scratch_, ip, nbuf); + reader_->Skip(peeked_); // All peeked bytes are used up + peeked_ = 0; + ip_ = scratch_; + ip_limit_ = scratch_ + nbuf; + } else { + // Pass pointer to buffer returned by reader_. + ip_ = ip; + } + return true; +} + +template +static bool InternalUncompress(Source* r, + Writer* writer, + uint32 max_len) { + // Read the uncompressed length from the front of the compressed input + SnappyDecompressor decompressor(r); + uint32 uncompressed_len = 0; + if (!decompressor.ReadUncompressedLength(&uncompressed_len)) return false; + return InternalUncompressAllTags( + &decompressor, writer, uncompressed_len, max_len); +} + +template +static bool InternalUncompressAllTags(SnappyDecompressor* decompressor, + Writer* writer, + uint32 uncompressed_len, + uint32 max_len) { + // Protect against possible DoS attack + if (static_cast(uncompressed_len) > max_len) { + return false; + } + + writer->SetExpectedLength(uncompressed_len); + + // Process the entire input + decompressor->DecompressAllTags(writer); + return (decompressor->eof() && writer->CheckLength()); +} + +bool GetUncompressedLength(Source* source, uint32* result) { + SnappyDecompressor decompressor(source); + return decompressor.ReadUncompressedLength(result); +} + +size_t Compress(Source* reader, Sink* writer) { + size_t written = 0; + size_t N = reader->Available(); + char ulength[Varint::kMax32]; + char* p = Varint::Encode32(ulength, N); + writer->Append(ulength, p-ulength); + written += (p - ulength); + + internal::WorkingMemory wmem; + char* scratch = NULL; + char* scratch_output = NULL; + + while (N > 0) { + // Get next block to compress (without copying if possible) + size_t fragment_size; + const char* fragment = reader->Peek(&fragment_size); + assert(fragment_size != 0); // premature end of input + const size_t num_to_read = min(N, kBlockSize); + size_t bytes_read = fragment_size; + + size_t pending_advance = 0; + if (bytes_read >= num_to_read) { + // Buffer returned by reader is large enough + pending_advance = num_to_read; + fragment_size = num_to_read; + } else { + // Read into scratch buffer + if (scratch == NULL) { + // If this is the last iteration, we want to allocate N bytes + // of space, otherwise the max possible kBlockSize space. + // num_to_read contains exactly the correct value + scratch = new char[num_to_read]; + } + memcpy(scratch, fragment, bytes_read); + reader->Skip(bytes_read); + + while (bytes_read < num_to_read) { + fragment = reader->Peek(&fragment_size); + size_t n = min(fragment_size, num_to_read - bytes_read); + memcpy(scratch + bytes_read, fragment, n); + bytes_read += n; + reader->Skip(n); + } + assert(bytes_read == num_to_read); + fragment = scratch; + fragment_size = num_to_read; + } + assert(fragment_size == num_to_read); + + // Get encoding table for compression + int table_size; + uint16* table = wmem.GetHashTable(num_to_read, &table_size); + + // Compress input_fragment and append to dest + const int max_output = MaxCompressedLength(num_to_read); + + // Need a scratch buffer for the output, in case the byte sink doesn't + // have room for us directly. + if (scratch_output == NULL) { + scratch_output = new char[max_output]; + } else { + // Since we encode kBlockSize regions followed by a region + // which is <= kBlockSize in length, a previously allocated + // scratch_output[] region is big enough for this iteration. + } + char* dest = writer->GetAppendBuffer(max_output, scratch_output); + char* end = internal::CompressFragment(fragment, fragment_size, + dest, table, table_size); + writer->Append(dest, end - dest); + written += (end - dest); + + N -= num_to_read; + reader->Skip(pending_advance); + } + + delete[] scratch; + delete[] scratch_output; + + return written; +} + +// ----------------------------------------------------------------------- +// Flat array interfaces +// ----------------------------------------------------------------------- + +// A type that writes to a flat array. +// Note that this is not a "ByteSink", but a type that matches the +// Writer template argument to SnappyDecompressor::DecompressAllTags(). +class SnappyArrayWriter { + private: + char* base_; + char* op_; + char* op_limit_; + + public: + inline explicit SnappyArrayWriter(char* dst) + : base_(dst), + op_(dst) { + } + + inline void SetExpectedLength(size_t len) { + op_limit_ = op_ + len; + } + + inline bool CheckLength() const { + return op_ == op_limit_; + } + + inline bool Append(const char* ip, size_t len) { + char* op = op_; + const size_t space_left = op_limit_ - op; + if (space_left < len) { + return false; + } + memcpy(op, ip, len); + op_ = op + len; + return true; + } + + inline bool TryFastAppend(const char* ip, size_t available, size_t len) { + char* op = op_; + const size_t space_left = op_limit_ - op; + if (len <= 16 && available >= 16 && space_left >= 16) { + // Fast path, used for the majority (about 95%) of invocations. + UnalignedCopy64(ip, op); + UnalignedCopy64(ip + 8, op + 8); + op_ = op + len; + return true; + } else { + return false; + } + } + + inline bool AppendFromSelf(size_t offset, size_t len) { + char* op = op_; + const size_t space_left = op_limit_ - op; + + if (op - base_ <= offset - 1u) { // -1u catches offset==0 + return false; + } + if (len <= 16 && offset >= 8 && space_left >= 16) { + // Fast path, used for the majority (70-80%) of dynamic invocations. + UnalignedCopy64(op - offset, op); + UnalignedCopy64(op - offset + 8, op + 8); + } else { + if (space_left >= len + kMaxIncrementCopyOverflow) { + IncrementalCopyFastPath(op - offset, op, len); + } else { + if (space_left < len) { + return false; + } + IncrementalCopy(op - offset, op, len); + } + } + + op_ = op + len; + return true; + } +}; + +bool RawUncompress(const char* compressed, size_t n, char* uncompressed) { + ByteArraySource reader(compressed, n); + return RawUncompress(&reader, uncompressed); +} + +bool RawUncompress(Source* compressed, char* uncompressed) { + SnappyArrayWriter output(uncompressed); + return InternalUncompress(compressed, &output, kuint32max); +} + +bool Uncompress(const char* compressed, size_t n, string* uncompressed) { + size_t ulength; + if (!GetUncompressedLength(compressed, n, &ulength)) { + return false; + } + // Protect against possible DoS attack + if ((static_cast(ulength) + uncompressed->size()) > + uncompressed->max_size()) { + return false; + } + STLStringResizeUninitialized(uncompressed, ulength); + return RawUncompress(compressed, n, string_as_array(uncompressed)); +} + + +// A Writer that drops everything on the floor and just does validation +class SnappyDecompressionValidator { + private: + size_t expected_; + size_t produced_; + + public: + inline SnappyDecompressionValidator() : produced_(0) { } + inline void SetExpectedLength(size_t len) { + expected_ = len; + } + inline bool CheckLength() const { + return expected_ == produced_; + } + inline bool Append(const char* ip, size_t len) { + produced_ += len; + return produced_ <= expected_; + } + inline bool TryFastAppend(const char* ip, size_t available, size_t length) { + return false; + } + inline bool AppendFromSelf(size_t offset, size_t len) { + if (produced_ <= offset - 1u) return false; // -1u catches offset==0 + produced_ += len; + return produced_ <= expected_; + } +}; + +bool IsValidCompressedBuffer(const char* compressed, size_t n) { + ByteArraySource reader(compressed, n); + SnappyDecompressionValidator writer; + return InternalUncompress(&reader, &writer, kuint32max); +} + +void RawCompress(const char* input, + size_t input_length, + char* compressed, + size_t* compressed_length) { + ByteArraySource reader(input, input_length); + UncheckedByteArraySink writer(compressed); + Compress(&reader, &writer); + + // Compute how many bytes were added + *compressed_length = (writer.CurrentDestination() - compressed); +} + +size_t Compress(const char* input, size_t input_length, string* compressed) { + // Pre-grow the buffer to the max length of the compressed output + compressed->resize(MaxCompressedLength(input_length)); + + size_t compressed_length; + RawCompress(input, input_length, string_as_array(compressed), + &compressed_length); + compressed->resize(compressed_length); + return compressed_length; +} + + +} // end namespace snappy + diff --git a/ext/snappy/snappy.h b/ext/snappy/snappy.h new file mode 100644 index 0000000000..d15ffbf0a8 --- /dev/null +++ b/ext/snappy/snappy.h @@ -0,0 +1,162 @@ +// Copyright 2005 and onwards Google Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// A light-weight compression algorithm. It is designed for speed of +// compression and decompression, rather than for the utmost in space +// savings. +// +// For getting better compression ratios when you are compressing data +// with long repeated sequences or compressing data that is similar to +// other data, while still compressing fast, you might look at first +// using BMDiff and then compressing the output of BMDiff with +// Snappy. + +#ifndef UTIL_SNAPPY_SNAPPY_H__ +#define UTIL_SNAPPY_SNAPPY_H__ + +#include +#include + +#include "snappy-stubs-public.h" + +namespace snappy { + class Source; + class Sink; + + // ------------------------------------------------------------------------ + // Generic compression/decompression routines. + // ------------------------------------------------------------------------ + + // Compress the bytes read from "*source" and append to "*sink". Return the + // number of bytes written. + size_t Compress(Source* source, Sink* sink); + + // Find the uncompressed length of the given stream, as given by the header. + // Note that the true length could deviate from this; the stream could e.g. + // be truncated. + // + // Also note that this leaves "*source" in a state that is unsuitable for + // further operations, such as RawUncompress(). You will need to rewind + // or recreate the source yourself before attempting any further calls. + bool GetUncompressedLength(Source* source, uint32* result); + + // ------------------------------------------------------------------------ + // Higher-level string based routines (should be sufficient for most users) + // ------------------------------------------------------------------------ + + // Sets "*output" to the compressed version of "input[0,input_length-1]". + // Original contents of *output are lost. + // + // REQUIRES: "input[]" is not an alias of "*output". + size_t Compress(const char* input, size_t input_length, string* output); + + // Decompresses "compressed[0,compressed_length-1]" to "*uncompressed". + // Original contents of "*uncompressed" are lost. + // + // REQUIRES: "compressed[]" is not an alias of "*uncompressed". + // + // returns false if the message is corrupted and could not be decompressed + bool Uncompress(const char* compressed, size_t compressed_length, + string* uncompressed); + + + // ------------------------------------------------------------------------ + // Lower-level character array based routines. May be useful for + // efficiency reasons in certain circumstances. + // ------------------------------------------------------------------------ + + // REQUIRES: "compressed" must point to an area of memory that is at + // least "MaxCompressedLength(input_length)" bytes in length. + // + // Takes the data stored in "input[0..input_length]" and stores + // it in the array pointed to by "compressed". + // + // "*compressed_length" is set to the length of the compressed output. + // + // Example: + // char* output = new char[snappy::MaxCompressedLength(input_length)]; + // size_t output_length; + // RawCompress(input, input_length, output, &output_length); + // ... Process(output, output_length) ... + // delete [] output; + void RawCompress(const char* input, + size_t input_length, + char* compressed, + size_t* compressed_length); + + // Given data in "compressed[0..compressed_length-1]" generated by + // calling the Snappy::Compress routine, this routine + // stores the uncompressed data to + // uncompressed[0..GetUncompressedLength(compressed)-1] + // returns false if the message is corrupted and could not be decrypted + bool RawUncompress(const char* compressed, size_t compressed_length, + char* uncompressed); + + // Given data from the byte source 'compressed' generated by calling + // the Snappy::Compress routine, this routine stores the uncompressed + // data to + // uncompressed[0..GetUncompressedLength(compressed,compressed_length)-1] + // returns false if the message is corrupted and could not be decrypted + bool RawUncompress(Source* compressed, char* uncompressed); + + // Returns the maximal size of the compressed representation of + // input data that is "source_bytes" bytes in length; + size_t MaxCompressedLength(size_t source_bytes); + + // REQUIRES: "compressed[]" was produced by RawCompress() or Compress() + // Returns true and stores the length of the uncompressed data in + // *result normally. Returns false on parsing error. + // This operation takes O(1) time. + bool GetUncompressedLength(const char* compressed, size_t compressed_length, + size_t* result); + + // Returns true iff the contents of "compressed[]" can be uncompressed + // successfully. Does not return the uncompressed data. Takes + // time proportional to compressed_length, but is usually at least + // a factor of four faster than actual decompression. + bool IsValidCompressedBuffer(const char* compressed, + size_t compressed_length); + + // *** DO NOT CHANGE THE VALUE OF kBlockSize *** + // + // New Compression code chops up the input into blocks of at most + // the following size. This ensures that back-references in the + // output never cross kBlockSize block boundaries. This can be + // helpful in implementing blocked decompression. However the + // decompression code should not rely on this guarantee since older + // compression code may not obey it. + static const int kBlockLog = 15; + static const size_t kBlockSize = 1 << kBlockLog; + + static const int kMaxHashTableBits = 14; + static const size_t kMaxHashTableSize = 1 << kMaxHashTableBits; + +} // end namespace snappy + + +#endif // UTIL_SNAPPY_SNAPPY_H__ From fb487ded17bf93b869f54e03326a6455b6c3a9e8 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Wed, 2 Jan 2013 22:57:57 +0100 Subject: [PATCH 64/89] Windows: Add ugly dialog that just shows controls for now. Also had VS rewrite the .rc file for me, looks neater. --- Windows/WndMainWindow.cpp | 58 ++++++- Windows/ppsspp.rc | 334 +++++++++++++++++++++++--------------- Windows/resource.h | 10 +- 3 files changed, 262 insertions(+), 140 deletions(-) diff --git a/Windows/WndMainWindow.cpp b/Windows/WndMainWindow.cpp index beec2a68c8..58a86caea6 100644 --- a/Windows/WndMainWindow.cpp +++ b/Windows/WndMainWindow.cpp @@ -61,6 +61,7 @@ namespace MainWindow LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK DisplayProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); + LRESULT CALLBACK Controls(HWND, UINT, WPARAM, LPARAM); HWND GetHWND() { @@ -543,10 +544,16 @@ namespace MainWindow g_Config.bFastMemory = !g_Config.bFastMemory; UpdateMenus(); break; - case ID_OPTIONS_LINEARFILTERING: + case ID_OPTIONS_LINEARFILTERING: g_Config.bLinearFiltering = !g_Config.bLinearFiltering; UpdateMenus(); break; + case ID_OPTIONS_CONTROLS: + DialogManager::EnableAll(FALSE); + DialogBox(hInst, (LPCTSTR)IDD_CONTROLS, hWnd, (DLGPROC)Controls); + DialogManager::EnableAll(TRUE); + break; + ////////////////////////////////////////////////////////////////////////// @@ -637,7 +644,7 @@ namespace MainWindow } else */ - return DefWindowProc(hWnd,message,wParam,lParam); + return DefWindowProc(hWnd,message,wParam,lParam); // case WM_LBUTTONDOWN: // TrackPopupMenu(menu,0,0,0,0,hWnd,0); // break; @@ -746,6 +753,53 @@ namespace MainWindow return FALSE; } + const char *controllist[] = { + "Start\tSpace", + "Select\tV", + "Square\tA", + "Triangle\tS", + "Circle\tX", + "Cross\tZ", + "Left Trigger\tQ", + "Right Trigger\tW", + "Up\tArrow Up", + "Down\tArrow Down", + "Left\tArrow Left", + "Right\tArrow Right", + "Analog Up\tI", + "Analog Down\tK", + "Analog Left\tJ", + "Analog Right\tL", + }; + // Message handler for about box. + LRESULT CALLBACK Controls(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) + { + switch (message) + { + case WM_INITDIALOG: + W32Util::CenterWindow(hDlg); + { + // TODO: connect to keyboard device instead + HWND list = GetDlgItem(hDlg, IDC_LISTCONTROLS); + int stops[1] = {80}; + SendMessage(list, LB_SETTABSTOPS, 1, (LPARAM)stops); + for (int i = 0; i < sizeof(controllist)/sizeof(controllist[0]); i++) { + SendMessage(list, LB_INSERTSTRING, -1, (LPARAM)controllist[i]); + } + } + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) + { + EndDialog(hDlg, LOWORD(wParam)); + return TRUE; + } + break; + } + return FALSE; + } + void Update() { InvalidateRect(hwndDisplay,0,0); diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 11fcf4fd43..8fccc169a5 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -1,15 +1,7 @@ // Microsoft Visual C++ generated resource script. // #include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS - #include "windows.h" - -#undef APSTUDIO_READONLY_SYMBOLS - -#define IDC_STATIC -1 - ///////////////////////////////////////////////////////////////////////////// // Neutral resources @@ -28,24 +20,24 @@ EXSTYLE WS_EX_ACCEPTFILES | WS_EX_TOOLWINDOW CAPTION "CPU" FONT 8, "MS Shell Dlg", 0, 0, 0x1 BEGIN - LTEXT "Ctr:",IDC_STATIC,6,2,12,8 - EDITTEXT IDC_DEBUG_COUNT,30,2,39,12,ES_UPPERCASE | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER - PUSHBUTTON "&Go",IDC_GO,111,0,24,14 - PUSHBUTTON "Stop",IDC_STOP,139,0,23,14 - DEFPUSHBUTTON "Step &Into",IDC_STEP,179,0,39,14 - PUSHBUTTON "Step &Over",IDC_STEPOVER,219,0,40,14 - PUSHBUTTON "S&kip",IDC_SKIP,265,0,23,14 - PUSHBUTTON "Next &HLE",IDC_STEPHLE,294,0,40,14 - EDITTEXT IDC_ADDRESS,11,24,91,13,ES_UPPERCASE | ES_AUTOHSCROLL - PUSHBUTTON "&PC",IDC_GOTOPC,11,40,15,13 - PUSHBUTTON "&LR",IDC_GOTOLR,28,40,14,13 - COMBOBOX IDC_GOTOINT,43,40,60,76,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - CONTROL "Custom1",IDC_DISASMVIEW,"CtrlDisAsmView",WS_BORDER | WS_TABSTOP,111,16,297,314 - GROUPBOX "&Go to",IDC_STATIC,5,12,102,47 - CONTROL "Custom1",IDC_REGLIST,"CtrlRegisterList",WS_BORDER | WS_TABSTOP,1,81,102,249 - CONTROL "",IDC_LEFTTABS,"SysTabControl32",TCS_BUTTONS,1,63,78,15 - LISTBOX IDC_FUNCTIONLIST,1,83,103,247,LBS_SORT | LBS_NOINTEGRALHEIGHT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "&VFPU",IDC_SHOWVFPU,83,63,24,12 + LTEXT "Ctr:",IDC_STATIC,6,2,12,8 + EDITTEXT IDC_DEBUG_COUNT,30,2,39,12,ES_UPPERCASE | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + PUSHBUTTON "&Go",IDC_GO,111,0,24,14 + PUSHBUTTON "Stop",IDC_STOP,139,0,23,14 + DEFPUSHBUTTON "Step &Into",IDC_STEP,179,0,39,14 + PUSHBUTTON "Step &Over",IDC_STEPOVER,219,0,40,14 + PUSHBUTTON "S&kip",IDC_SKIP,265,0,23,14 + PUSHBUTTON "Next &HLE",IDC_STEPHLE,294,0,40,14 + EDITTEXT IDC_ADDRESS,11,24,91,13,ES_UPPERCASE | ES_AUTOHSCROLL + PUSHBUTTON "&PC",IDC_GOTOPC,11,40,15,13 + PUSHBUTTON "&LR",IDC_GOTOLR,28,40,14,13 + COMBOBOX IDC_GOTOINT,43,40,60,76,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "Custom1",IDC_DISASMVIEW,"CtrlDisAsmView",WS_BORDER | WS_TABSTOP,111,16,297,314 + GROUPBOX "&Go to",IDC_STATIC,5,12,102,47 + CONTROL "Custom1",IDC_REGLIST,"CtrlRegisterList",WS_BORDER | WS_TABSTOP,1,81,102,249 + CONTROL "",IDC_LEFTTABS,"SysTabControl32",TCS_BUTTONS,1,63,78,15 + LISTBOX IDC_FUNCTIONLIST,1,83,103,247,LBS_SORT | LBS_NOINTEGRALHEIGHT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "&VFPU",IDC_SHOWVFPU,83,63,24,12 END IDD_ABOUTBOX DIALOGEX 0, 0, 301, 163 @@ -53,16 +45,16 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPT CAPTION "About" FONT 8, "MS Shell Dlg", 0, 0, 0x0 BEGIN - DEFPUSHBUTTON "OK",IDOK,243,141,50,14 - ICON IDI_PPSSPP,IDC_STATIC,10,9,20,20 - LTEXT "PPSSPP",IDC_STATIC,40,8,127,9 - LTEXT "Copyright (c) by Henrik RydgÃ¥rd 2012",IDC_STATIC,40,33,253,8 - LTEXT "All trademarks are property of their respective owners.\nThe emulator is for educational and development purposes only and it may not be used to play games you do not legally own.",IDC_STATIC,40,102,253,24 - LTEXT "PSP emulator and debugger",IDC_STATIC,40,19,253,8 - LTEXT "CISO decompression code by BOOSTER",IDC_STATIC,48,73,240,8 - LTEXT "PSPSDK by #pspdev (freenode)",IDC_STATIC,48,62,240,8 - LTEXT "zlib by Jean-loup Gailly (compression) and Mark Adler (decompression)",IDC_STATIC,48,85,240,8 - LTEXT "Additional credits:",IDC_STATIC,40,49,253,8 + DEFPUSHBUTTON "OK",IDOK,243,141,50,14 + ICON IDI_PPSSPP,IDC_STATIC,10,9,20,20 + LTEXT "PPSSPP",IDC_STATIC,40,8,127,9 + LTEXT "Copyright (c) by Henrik RydgÃ¥rd 2012",IDC_STATIC,40,33,253,8 + LTEXT "All trademarks are property of their respective owners.\nThe emulator is for educational and development purposes only and it may not be used to play games you do not legally own.",IDC_STATIC,40,102,253,24 + LTEXT "PSP emulator and debugger",IDC_STATIC,40,19,253,8 + LTEXT "CISO decompression code by BOOSTER",IDC_STATIC,48,73,240,8 + LTEXT "PSPSDK by #pspdev (freenode)",IDC_STATIC,48,62,240,8 + LTEXT "zlib by Jean-loup Gailly (compression) and Mark Adler (decompression)",IDC_STATIC,48,85,240,8 + LTEXT "Additional credits:",IDC_STATIC,40,49,253,8 END IDD_MEMORY DIALOGEX 0, 0, 444, 287 @@ -71,14 +63,14 @@ EXSTYLE WS_EX_TOOLWINDOW CAPTION "Memory View" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "Goto:",IDC_STATIC,4,7,17,8 - EDITTEXT IDC_ADDRESS,23,5,61,13,ES_AUTOHSCROLL - CONTROL "Custom2",IDC_MEMVIEW,"CtrlMemView",WS_BORDER | WS_TABSTOP,126,23,316,263 - LISTBOX IDC_SYMBOLS,1,23,120,263,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - CONTROL "&Normal",IDC_MODENORMAL,"Button",BS_AUTORADIOBUTTON | WS_GROUP,248,9,40,9 - CONTROL "&Symbols",IDC_MODESYMBOLS,"Button",BS_AUTORADIOBUTTON,291,9,43,8 - GROUPBOX "Mode",IDC_STATIC,241,0,104,22 - COMBOBOX IDC_REGIONS,87,5,88,139,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Goto:",IDC_STATIC,4,7,17,8 + EDITTEXT IDC_ADDRESS,23,5,61,13,ES_AUTOHSCROLL + CONTROL "Custom2",IDC_MEMVIEW,"CtrlMemView",WS_BORDER | WS_TABSTOP,126,23,316,263 + LISTBOX IDC_SYMBOLS,1,23,120,263,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + CONTROL "&Normal",IDC_MODENORMAL,"Button",BS_AUTORADIOBUTTON | WS_GROUP,248,9,40,9 + CONTROL "&Symbols",IDC_MODESYMBOLS,"Button",BS_AUTORADIOBUTTON,291,9,43,8 + GROUPBOX "Mode",IDC_STATIC,241,0,104,22 + COMBOBOX IDC_REGIONS,87,5,88,139,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP END IDD_INPUTBOX DIALOGEX 0, 0, 163, 55 @@ -86,10 +78,10 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Change value" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "&New value",IDC_VALUENAME,7,7,89,8 - EDITTEXT IDC_INPUTBOX,7,16,149,13,ES_AUTOHSCROLL - DEFPUSHBUTTON "OK",IDOK,51,34,50,14 - PUSHBUTTON "Cancel",IDCANCEL,106,34,50,14 + LTEXT "&New value",IDC_VALUENAME,7,7,89,8 + EDITTEXT IDC_INPUTBOX,7,16,149,13,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,51,34,50,14 + PUSHBUTTON "Cancel",IDCANCEL,106,34,50,14 END IDD_VFPU DIALOGEX 0, 0, 250, 420 @@ -98,7 +90,7 @@ EXSTYLE WS_EX_PALETTEWINDOW CAPTION "VFPU" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "",IDC_TABDATATYPE,"SysTabControl32",TCS_BUTTONS,0,1,205,15 + CONTROL "",IDC_TABDATATYPE,"SysTabControl32",TCS_BUTTONS,0,1,205,15 END @@ -151,7 +143,7 @@ BEGIN BOTTOMMARGIN, 413 END END -#endif // APSTUDIO_INVOKED +#endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// @@ -161,10 +153,10 @@ END // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. -IDI_PPSSPP ICON "ppsspp.ico" -IDI_STOP ICON "icon1.ico" -IDI_STOPDISABLE ICON "stop1.ico" -#endif // Neutral resources +IDI_PPSSPP ICON "ppsspp.ico" +IDI_STOP ICON "icon1.ico" +IDI_STOPDISABLE ICON "stop1.ico" +#endif // Neutral resources ///////////////////////////////////////////////////////////////////////////// @@ -184,75 +176,145 @@ IDR_MENU1 MENU BEGIN POPUP "&File" BEGIN - MENUITEM "&Open...", ID_FILE_LOAD - MENUITEM "&Close", ID_EMULATION_STOP + MENUITEM "&Open...", ID_FILE_LOAD + MENUITEM "&Close", ID_EMULATION_STOP MENUITEM SEPARATOR - MENUITEM "Quickload state\tF4" ID_FILE_QUICKLOADSTATE - MENUITEM "Quicksave state\tF2" ID_FILE_QUICKSAVESTATE - MENUITEM "&Load State File..." ID_FILE_LOADSTATEFILE - MENUITEM "&Save State File..." ID_FILE_SAVESTATEFILE + MENUITEM "Quickload state\tF4", ID_FILE_QUICKLOADSTATE + MENUITEM "Quicksave state\tF2", ID_FILE_QUICKSAVESTATE + MENUITEM "&Load State File...", ID_FILE_LOADSTATEFILE + MENUITEM "&Save State File...", ID_FILE_SAVESTATEFILE MENUITEM SEPARATOR - MENUITEM "E&xit", ID_FILE_EXIT + MENUITEM "E&xit", ID_FILE_EXIT END POPUP "&Emulation" BEGIN - MENUITEM "&Run\tF7", ID_EMULATION_RUN - MENUITEM "&Pause\tF8", ID_EMULATION_PAUSE + MENUITEM "&Run\tF7", ID_EMULATION_RUN + MENUITEM "&Pause\tF8", ID_EMULATION_PAUSE MENUITEM SEPARATOR - MENUITEM "R&eset", ID_EMULATION_RESET + MENUITEM "R&eset", ID_EMULATION_RESET MENUITEM SEPARATOR - MENUITEM "&Interpreter", ID_CPU_INTERPRETER + MENUITEM "&Interpreter", ID_CPU_INTERPRETER MENUITEM "&Slightly Faster Interpreter", ID_CPU_FASTINTERPRETER - MENUITEM "&Dynarec", ID_CPU_DYNAREC, CHECKED + MENUITEM "&Dynarec", ID_CPU_DYNAREC, CHECKED END POPUP "Debu&g" BEGIN - MENUITEM "Load &Map File...", ID_DEBUG_LOADMAPFILE - MENUITEM "&Save Map File...", ID_DEBUG_SAVEMAPFILE - MENUITEM "&Reset Symbol Table", ID_DEBUG_RESETSYMBOLTABLE + MENUITEM "Load &Map File...", ID_DEBUG_LOADMAPFILE + MENUITEM "&Save Map File...", ID_DEBUG_SAVEMAPFILE + MENUITEM "&Reset Symbol Table", ID_DEBUG_RESETSYMBOLTABLE MENUITEM SEPARATOR - MENUITEM "&Disassembly\tCtrl+D", ID_DEBUG_DISASSEMBLY - MENUITEM "&Log Console\tCtrl+L", ID_DEBUG_LOG - MENUITEM "Memory &View...\tCtrl+M", ID_DEBUG_MEMORYVIEW + MENUITEM "&Disassembly\tCtrl+D", ID_DEBUG_DISASSEMBLY + MENUITEM "&Log Console\tCtrl+L", ID_DEBUG_LOG + MENUITEM "Memory &View...\tCtrl+M", ID_DEBUG_MEMORYVIEW END POPUP "&Options" BEGIN - MENUITEM "&Toggle Full Screen\tF12", ID_OPTIONS_FULLSCREEN - MENUITEM "&Display Raw Framebuffer", ID_OPTIONS_DISPLAYRAWFRAMEBUFFER - MENUITEM "&Buffered Rendering\tF5", ID_OPTIONS_BUFFEREDRENDERING - MENUITEM "&Hardware Transform\tF6", ID_OPTIONS_HARDWARETRANSFORM - MENUITEM "&Linear Filtering", ID_OPTIONS_LINEARFILTERING + MENUITEM "&Controls", ID_OPTIONS_CONTROLS + MENUITEM SEPARATOR + MENUITEM "&Toggle Full Screen\tF12", ID_OPTIONS_FULLSCREEN + MENUITEM "&Buffered Rendering\tF5", ID_OPTIONS_BUFFEREDRENDERING + MENUITEM "&Hardware Transform\tF6", ID_OPTIONS_HARDWARETRANSFORM + MENUITEM "&Linear Filtering", ID_OPTIONS_LINEARFILTERING + MENUITEM SEPARATOR + MENUITEM "&Wireframe (experimental)", ID_OPTIONS_WIREFRAME + MENUITEM "&Display Raw Framebuffer", ID_OPTIONS_DISPLAYRAWFRAMEBUFFER + MENUITEM "&Show Debug Statistics", ID_OPTIONS_SHOWDEBUGSTATISTICS + MENUITEM SEPARATOR + MENUITEM "Screen &1x\tCtrl+1", ID_OPTIONS_SCREEN1X + MENUITEM "Screen &2x\tCtrl+2", ID_OPTIONS_SCREEN2X + MENUITEM "Screen &3x\tCtrl+3", ID_OPTIONS_SCREEN3X + MENUITEM "Screen &4x\tCtrl+4", ID_OPTIONS_SCREEN4X + MENUITEM SEPARATOR MENUITEM "&Fast Memory (dynarec, unstable)", ID_OPTIONS_FASTMEMORY - MENUITEM "&Wireframe (experimental)", ID_OPTIONS_WIREFRAME - MENUITEM "&Show Debug Statistics", ID_OPTIONS_SHOWDEBUGSTATISTICS - MENUITEM SEPARATOR - MENUITEM "Screen &1x\tCtrl+1", ID_OPTIONS_SCREEN1X - MENUITEM "Screen &2x\tCtrl+2", ID_OPTIONS_SCREEN2X - MENUITEM "Screen &3x\tCtrl+3", ID_OPTIONS_SCREEN3X - MENUITEM "Screen &4x\tCtrl+4", ID_OPTIONS_SCREEN4X - MENUITEM SEPARATOR MENUITEM "&Ignore illegal reads/writes", ID_OPTIONS_IGNOREILLEGALREADS END POPUP "&Help" BEGIN MENUITEM "&Go to http://www.ppsspp.org/", ID_HELP_OPENWEBSITE MENUITEM SEPARATOR - MENUITEM "&About PPSSPP...", ID_HELP_ABOUT + MENUITEM "&About PPSSPP...", ID_HELP_ABOUT END END -#endif // Neutral (Default) resources +#endif // Neutral (Default) resources ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUD) +LANGUAGE LANG_NEUTRAL, SUBLANG_DEFAULT +#pragma code_page(1252) +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONTROLS DIALOGEX 0, 0, 287, 238 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Controls" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,176,217,50,14 + PUSHBUTTON "Cancel",IDCANCEL,230,217,50,14 + LTEXT "NOTE: Currently controls are NOT configurable.",IDC_STATIC,7,7,188,10 + LISTBOX IDC_LISTCONTROLS,7,19,273,184,LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_USETABSTOPS | WS_VSCROLL | WS_TABSTOP +END ///////////////////////////////////////////////////////////////////////////// -// Swedish (Sweden) resources +// +// DESIGNINFO +// -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_SVE) -LANGUAGE LANG_SWEDISH, SUBLANG_SWEDISH +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CONTROLS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 280 + TOPMARGIN, 7 + BOTTOMMARGIN, 231 + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUD) +LANGUAGE LANG_NEUTRAL, SUBLANG_DEFAULT #pragma code_page(1252) ///////////////////////////////////////////////////////////////////////////// @@ -264,39 +326,39 @@ IDR_POPUPMENUS MENU BEGIN POPUP "memview" BEGIN - MENUITEM "Go to in &Disasm", ID_MEMVIEW_GOTOINDISASM + MENUITEM "Go to in &Disasm", ID_MEMVIEW_GOTOINDISASM MENUITEM SEPARATOR - MENUITEM "&Copy value", ID_MEMVIEW_COPYVALUE - MENUITEM "&Dump...", ID_MEMVIEW_DUMP + MENUITEM "&Copy value", ID_MEMVIEW_COPYVALUE + MENUITEM "&Dump...", ID_MEMVIEW_DUMP END POPUP "disasm" BEGIN - MENUITEM "Copy &address", ID_DISASM_COPYADDRESS - MENUITEM "Copy instruction (&hex)", ID_DISASM_COPYINSTRUCTIONHEX - MENUITEM "Copy instruction (&disasm)", ID_DISASM_COPYINSTRUCTIONDISASM + MENUITEM "Copy &address", ID_DISASM_COPYADDRESS + MENUITEM "Copy instruction (&hex)", ID_DISASM_COPYINSTRUCTIONHEX + MENUITEM "Copy instruction (&disasm)", ID_DISASM_COPYINSTRUCTIONDISASM MENUITEM SEPARATOR - MENUITEM "&Run to here", ID_DISASM_RUNTOHERE - MENUITEM "&Set Next Statement", ID_DISASM_SETPCTOHERE - MENUITEM "&Toggle breakpoint", ID_DISASM_TOGGLEBREAKPOINT - MENUITEM "&Follow branch", ID_DISASM_FOLLOWBRANCH + MENUITEM "&Run to here", ID_DISASM_RUNTOHERE + MENUITEM "&Set Next Statement", ID_DISASM_SETPCTOHERE + MENUITEM "&Toggle breakpoint", ID_DISASM_TOGGLEBREAKPOINT + MENUITEM "&Follow branch", ID_DISASM_FOLLOWBRANCH MENUITEM SEPARATOR - MENUITEM "&Show Dynarec Results", ID_DISASM_DYNARECRESULTS - MENUITEM "Go to in &Memory View", ID_DISASM_GOTOINMEMORYVIEW + MENUITEM "&Show Dynarec Results", ID_DISASM_DYNARECRESULTS + MENUITEM "Go to in &Memory View", ID_DISASM_GOTOINMEMORYVIEW MENUITEM SEPARATOR - MENUITEM "&Kill function", ID_DISASM_ADDHLE - MENUITEM "&Rename function...", ID_DISASM_RENAMEFUNCTION + MENUITEM "&Kill function", ID_DISASM_ADDHLE + MENUITEM "&Rename function...", ID_DISASM_RENAMEFUNCTION END POPUP "funclist" BEGIN - MENUITEM "&Kill function", ID_FUNCLIST_KILLFUNCTION + MENUITEM "&Kill function", ID_FUNCLIST_KILLFUNCTION END POPUP "reglist" BEGIN - MENUITEM "Go to in &memory view", ID_REGLIST_GOTOINMEMORYVIEW - MENUITEM "Go to in &disasm", ID_REGLIST_GOTOINDISASM + MENUITEM "Go to in &memory view", ID_REGLIST_GOTOINMEMORYVIEW + MENUITEM "Go to in &disasm", ID_REGLIST_GOTOINDISASM MENUITEM SEPARATOR - MENUITEM "&Copy value", ID_REGLIST_COPYVALUE - MENUITEM "C&hange...", ID_REGLIST_CHANGE + MENUITEM "&Copy value", ID_REGLIST_COPYVALUE + MENUITEM "C&hange...", ID_REGLIST_CHANGE END END @@ -306,7 +368,7 @@ END // RT_MANIFEST // -1 RT_MANIFEST "rt_manif.bin" +1 RT_MANIFEST "rt_manif.bin" ///////////////////////////////////////////////////////////////////////////// // @@ -315,24 +377,24 @@ END IDR_ACCELS ACCELERATORS BEGIN - "D", ID_DEBUG_DISASSEMBLY, VIRTKEY, CONTROL, NOINVERT - "L", ID_DEBUG_LOG, VIRTKEY, CONTROL, NOINVERT - "E", ID_DEBUG_MEMORYCHECKS, VIRTKEY, CONTROL, NOINVERT - "F", ID_DEBUG_MEMORYSEARCH, VIRTKEY, CONTROL, NOINVERT - "M", ID_DEBUG_MEMORYVIEW, VIRTKEY, CONTROL, NOINVERT - "R", ID_DEBUG_REGISTERS, VIRTKEY, CONTROL, NOINVERT - VK_F7, ID_EMULATION_RUN, VIRTKEY, NOINVERT - VK_F8, ID_EMULATION_PAUSE, VIRTKEY, NOINVERT - VK_F2, ID_FILE_QUICKSAVESTATE, VIRTKEY, NOINVERT - VK_F4, ID_FILE_QUICKLOADSTATE, VIRTKEY, NOINVERT - "1", ID_OPTIONS_SCREEN1X, VIRTKEY, CONTROL, NOINVERT - "2", ID_OPTIONS_SCREEN2X, VIRTKEY, CONTROL, NOINVERT - "3", ID_OPTIONS_SCREEN3X, VIRTKEY, CONTROL, NOINVERT - "4", ID_OPTIONS_SCREEN4X, VIRTKEY, CONTROL, NOINVERT - VK_F5, ID_OPTIONS_BUFFEREDRENDERING, VIRTKEY, NOINVERT - VK_F6, ID_OPTIONS_HARDWARETRANSFORM, VIRTKEY, NOINVERT - "W", ID_FILE_UNLOAD, VIRTKEY, CONTROL, NOINVERT - VK_F12, ID_OPTIONS_FULLSCREEN, VIRTKEY, NOINVERT + "D", ID_DEBUG_DISASSEMBLY, VIRTKEY, CONTROL, NOINVERT + "L", ID_DEBUG_LOG, VIRTKEY, CONTROL, NOINVERT + "E", ID_DEBUG_MEMORYCHECKS, VIRTKEY, CONTROL, NOINVERT + "F", ID_DEBUG_MEMORYSEARCH, VIRTKEY, CONTROL, NOINVERT + "M", ID_DEBUG_MEMORYVIEW, VIRTKEY, CONTROL, NOINVERT + "R", ID_DEBUG_REGISTERS, VIRTKEY, CONTROL, NOINVERT + VK_F7, ID_EMULATION_RUN, VIRTKEY, NOINVERT + VK_F8, ID_EMULATION_PAUSE, VIRTKEY, NOINVERT + VK_F2, ID_FILE_QUICKSAVESTATE, VIRTKEY, NOINVERT + VK_F4, ID_FILE_QUICKLOADSTATE, VIRTKEY, NOINVERT + "1", ID_OPTIONS_SCREEN1X, VIRTKEY, CONTROL, NOINVERT + "2", ID_OPTIONS_SCREEN2X, VIRTKEY, CONTROL, NOINVERT + "3", ID_OPTIONS_SCREEN3X, VIRTKEY, CONTROL, NOINVERT + "4", ID_OPTIONS_SCREEN4X, VIRTKEY, CONTROL, NOINVERT + VK_F5, ID_OPTIONS_BUFFEREDRENDERING, VIRTKEY, NOINVERT + VK_F6, ID_OPTIONS_HARDWARETRANSFORM, VIRTKEY, NOINVERT + "W", ID_FILE_UNLOAD, VIRTKEY, CONTROL, NOINVERT + VK_F12, ID_OPTIONS_FULLSCREEN, VIRTKEY, NOINVERT END @@ -384,18 +446,18 @@ END STRINGTABLE BEGIN - IDS_GAMELISTPATH "Path" - IDS_UNIMPLEMENTED "Unimplemented" + IDS_GAMELISTPATH "Path" + IDS_UNIMPLEMENTED "Unimplemented" END STRINGTABLE BEGIN - IDS_GAMELISTGENRE "Genre" - IDS_APPNAME "Potemkin" - IDS_GAMELISTTYPE "Type" + IDS_GAMELISTGENRE "Genre" + IDS_APPNAME "Potemkin" + IDS_GAMELISTTYPE "Type" END -#endif // Swedish (Sweden) resources +#endif // Neutral resources ///////////////////////////////////////////////////////////////////////////// @@ -405,6 +467,8 @@ END // // Generated from the TEXTINCLUDE 3 resource. // + + ///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED +#endif // not APSTUDIO_INVOKED diff --git a/Windows/resource.h b/Windows/resource.h index 79b18ad927..57c1cb4c7d 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -107,6 +107,7 @@ #define IDI_STOP 223 #define IDD_INPUTBOX 226 #define IDD_VFPU 231 +#define IDD_CONTROLS 232 #define IDC_GO 1001 #define IDC_ADDRESS 1002 #define IDC_DEBUG_COUNT 1003 @@ -154,6 +155,7 @@ #define IDC_FILELIST 1150 #define IDC_BROWSE 1159 #define IDC_SHOWVFPU 1161 +#define IDC_LISTCONTROLS 1162 #define ID_FILE_BOOTISO 40001 #define ID_FILE_EXIT 40002 #define ID_CONFIG_SELECT_PLUGINS 40003 @@ -250,14 +252,16 @@ #define ID_OPTIONS_LINEARFILTERING 40127 #define ID_FILE_QUICKSAVESTATE 40128 #define ID_FILE_QUICKLOADSTATE 40129 +#define ID_OPTIONS_CONTROLS 40130 +#define IDC_STATIC -1 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 232 -#define _APS_NEXT_COMMAND_VALUE 40130 -#define _APS_NEXT_CONTROL_VALUE 1162 +#define _APS_NEXT_RESOURCE_VALUE 233 +#define _APS_NEXT_COMMAND_VALUE 40131 +#define _APS_NEXT_CONTROL_VALUE 1163 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif From 65ddd4d731d92c04bb3574221f9ddb7638831a17 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 2 Jan 2013 14:25:35 -0800 Subject: [PATCH 65/89] Fix --state not loading a savestate on startup. Was scheduling some random event instead after 883f61e3ddafc0de17cb78f355f860e8ce4406a6. --- Core/SaveState.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index 215dda6451..bf4a2a8fde 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -58,6 +58,7 @@ namespace SaveState }; static int timer; + static bool needsProcess = false; static std::vector pending; static std::recursive_mutex mutex; @@ -93,8 +94,10 @@ namespace SaveState // Warning: this may run on a different thread. Process(0, 0); } - else + else if (__KernelIsRunning()) CoreTiming::ScheduleEvent_Threadsafe(0, timer); + else + needsProcess = true; } void Load(const std::string &filename, Callback callback, void *cbUserData) @@ -249,5 +252,12 @@ namespace SaveState timer = CoreTiming::RegisterEvent("SaveState", Process); // Make sure there's a directory for save slots pspFileSystem.MkDir("ms0:/PSP/PPSSPP_STATE"); + + std::lock_guard guard(mutex); + if (needsProcess) + { + CoreTiming::ScheduleEvent(0, timer); + needsProcess = false; + } } } From 895a36af19eeb446db6b5f4947bbe38068cd0742 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 3 Jan 2013 00:53:11 +0100 Subject: [PATCH 66/89] Add the new utf8.cpp to the main CMakeLists --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index acc8d2611b..d12ef4cb9c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -546,6 +546,8 @@ add_library(native STATIC native/util/random/perlin.cpp native/util/random/perlin.h native/util/random/rng.h + native/util/text/utf8.h + native/util/text/utf8.cpp native/ext/rapidxml/rapidxml.hpp native/ext/rapidxml/rapidxml_iterators.hpp native/ext/rapidxml/rapidxml_print.hpp From c3679166e5b5d99b8454355f376ed3e34eca06b1 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 3 Jan 2013 10:19:18 +0100 Subject: [PATCH 67/89] Fix flicker in a bunch of games. Fix is a little hacky but okay for 0.5. --- GPU/GLES/DisplayListInterpreter.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/GPU/GLES/DisplayListInterpreter.cpp b/GPU/GLES/DisplayListInterpreter.cpp index 35f7109ea3..85e13abf12 100644 --- a/GPU/GLES/DisplayListInterpreter.cpp +++ b/GPU/GLES/DisplayListInterpreter.cpp @@ -302,7 +302,16 @@ GLES_GPU::VirtualFramebuffer *GLES_GPU::GetDisplayFBO() { return *iter; } } - + DEBUG_LOG(HLE, "Finding no FBO matching address %08x", displayFramebufPtr_); +#ifdef _DEBUG + std::string debug = "FBOs: "; + for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter) { + char temp[256]; + sprintf(temp, "%08x %i %i", (*iter)->fb_address, (*iter)->width, (*iter)->height); + debug += std::string(temp); + } + ERROR_LOG(HLE, "FBOs: %s", debug.c_str()); +#endif return 0; } @@ -320,13 +329,19 @@ void GLES_GPU::SetRenderFrameBuffer() { int drawing_width = ((gstate.region2) & 0x3FF) + 1; int drawing_height = ((gstate.region2 >> 10) & 0x3FF) + 1; + // HACK for first frame where some games don't init things right + if (drawing_width == 1 && drawing_height == 1) { + drawing_width = 480; + drawing_height = 272; + } + int fmt = gstate.framebufpixformat & 3; // Find a matching framebuffer VirtualFramebuffer *vfb = 0; for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter) { VirtualFramebuffer *v = *iter; - if (v->fb_address == fb_address) { + if (v->fb_address == fb_address && v->width == drawing_width && v->height == drawing_height) { // Let's not be so picky for now. Let's say this is the one. vfb = v; // Update fb stride in case it changed @@ -353,7 +368,7 @@ void GLES_GPU::SetRenderFrameBuffer() { glViewport(0, 0, renderWidth_, renderHeight_); currentRenderVfb_ = vfb; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - DEBUG_LOG(HLE, "Creating FBO for %08x", vfb->fb_address); + INFO_LOG(HLE, "Creating FBO for %08x : %i x %i", vfb->fb_address, vfb->width, vfb->height); return; } From e3ee83c6a630b09956322165a47353e0ed2107aa Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 3 Jan 2013 12:04:00 +0100 Subject: [PATCH 68/89] Add option for 2x buffered rendering on Android. --- android/jni/EmuScreen.cpp | 6 ++++-- android/jni/MenuScreens.cpp | 15 ++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/android/jni/EmuScreen.cpp b/android/jni/EmuScreen.cpp index 69a3696b09..9b02a97bd9 100644 --- a/android/jni/EmuScreen.cpp +++ b/android/jni/EmuScreen.cpp @@ -59,8 +59,10 @@ EmuScreen::EmuScreen(const std::string &filename) : invalid_(true) coreParam.enableDebugging = false; coreParam.printfEmuLog = false; coreParam.headLess = false; - coreParam.renderWidth = 480; - coreParam.renderHeight = 272; + if (g_Config.iWindowZoom < 1 || g_Config.iWindowZoom > 2) + g_Config.iWindowZoom = 1; + coreParam.renderWidth = 480 * g_Config.iWindowZoom; + coreParam.renderHeight = 272 * g_Config.iWindowZoom; coreParam.outputWidth = dp_xres; coreParam.outputHeight = dp_yres; coreParam.pixelWidth = pixel_xres; diff --git a/android/jni/MenuScreens.cpp b/android/jni/MenuScreens.cpp index 1d22f0ac52..c0316b32c8 100644 --- a/android/jni/MenuScreens.cpp +++ b/android/jni/MenuScreens.cpp @@ -275,14 +275,19 @@ void SettingsScreen::render() { // VLinear vlinear(10, 80, 10); int x = 30; int y = 50; - UICheckBox(GEN_ID, x, y += 50, "Sound Emulation", ALIGN_TOPLEFT, &g_Config.bEnableSound); - UICheckBox(GEN_ID, x, y += 50, "Buffered Rendering (may fix flicker)", ALIGN_TOPLEFT, &g_Config.bBufferedRendering); - UICheckBox(GEN_ID, x, y += 50, "Hardware Transform", ALIGN_TOPLEFT, &g_Config.bHardwareTransform); + UICheckBox(GEN_ID, x, y += 45, "Sound Emulation", ALIGN_TOPLEFT, &g_Config.bEnableSound); + UICheckBox(GEN_ID, x, y += 45, "Buffered Rendering", ALIGN_TOPLEFT, &g_Config.bBufferedRendering); + if (g_Config.bBufferedRendering) { + bool doubleRes = g_Config.iWindowZoom == 2; + UICheckBox(GEN_ID, x + 50, y += 50, "2x Render Resolution", ALIGN_TOPLEFT, &doubleRes); + g_Config.iWindowZoom = doubleRes ? 2 : 1; + } + UICheckBox(GEN_ID, x, y += 45, "Hardware Transform", ALIGN_TOPLEFT, &g_Config.bHardwareTransform); bool useFastInt = g_Config.iCpuCore == CPU_FASTINTERPRETER; - UICheckBox(GEN_ID, x, y += 50, "Slightly faster interpreter (may crash)", ALIGN_TOPLEFT, &useFastInt); + UICheckBox(GEN_ID, x, y += 45, "Slightly faster interpreter (may crash)", ALIGN_TOPLEFT, &useFastInt); // ui_draw2d.DrawText(UBUNTU48, "much faster JIT coming later", x, y+=50, 0xcFFFFFFF, ALIGN_LEFT); - UICheckBox(GEN_ID, x, y += 50, "On-screen Touch Controls", ALIGN_TOPLEFT, &g_Config.bShowTouchControls); + UICheckBox(GEN_ID, x, y += 45, "On-screen Touch Controls", ALIGN_TOPLEFT, &g_Config.bShowTouchControls); if (g_Config.bShowTouchControls) UICheckBox(GEN_ID, x + 50, y += 50, "Show Analog Stick", ALIGN_TOPLEFT, &g_Config.bShowAnalogStick); g_Config.iCpuCore = useFastInt ? CPU_FASTINTERPRETER : CPU_INTERPRETER; From 98fd2027309ffd6fab3d9ac5b8cfb2f45ab0e57b Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 3 Jan 2013 12:04:40 +0100 Subject: [PATCH 69/89] Constify a couple of globals --- Core/ELF/PrxDecrypter.cpp | 8 ++++---- ext/libkirk/AES.c | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Core/ELF/PrxDecrypter.cpp b/Core/ELF/PrxDecrypter.cpp index 38ddc980f9..248d27f2b4 100644 --- a/Core/ELF/PrxDecrypter.cpp +++ b/Core/ELF/PrxDecrypter.cpp @@ -454,7 +454,7 @@ struct TAG_INFO2 u8 type; }; -static TAG_INFO2 g_tagInfo2[] = +static const TAG_INFO2 g_tagInfo2[] = { { 0x4C9494F0, keys660_k1, 0x43 }, { 0x4C9495F0, keys660_k2, 0x43 }, @@ -590,7 +590,7 @@ static TAG_INFO2 g_tagInfo2[] = }; -static TAG_INFO2 *GetTagInfo2(u32 tagFind) +static const TAG_INFO2 *GetTagInfo2(u32 tagFind) { for (u32 iTag = 0; iTag < sizeof(g_tagInfo2) / sizeof(TAG_INFO2); iTag++) { @@ -605,7 +605,7 @@ static TAG_INFO2 *GetTagInfo2(u32 tagFind) static int DecryptPRX2(const u8 *inbuf, u8 *outbuf, u32 size, u32 tag) { - TAG_INFO2 * pti = GetTagInfo2(tag); + const TAG_INFO2 *pti = GetTagInfo2(tag); if (!pti) { @@ -632,7 +632,7 @@ static int DecryptPRX2(const u8 *inbuf, u8 *outbuf, u32 size, u32 tag) return -2; } - if ((size - 0x150) < retsize) + if (((int)size - 0x150) < retsize) { return -4; } diff --git a/ext/libkirk/AES.c b/ext/libkirk/AES.c index fc80f348b9..c75748510b 100644 --- a/ext/libkirk/AES.c +++ b/ext/libkirk/AES.c @@ -37,11 +37,11 @@ //CMAC GLOBS #define AES_128 0 -unsigned char const_Rb[16] = { +const unsigned char const_Rb[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87 }; -unsigned char const_Zero[16] = { +const unsigned char const_Zero[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -1294,7 +1294,7 @@ void AES_encrypt(AES_ctx *ctx, const u8 *src, u8 *dst) rijndaelEncrypt(ctx->ek, ctx->Nr, src, dst); } -void xor_128(unsigned char *a, unsigned char *b, unsigned char *out) +void xor_128(const unsigned char *a, const unsigned char *b, unsigned char *out) { int i; for (i=0;i<16; i++) From 4e37c5ab4d2a118b5c91aae831f0b2952d193975 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 3 Jan 2013 12:05:39 +0100 Subject: [PATCH 70/89] Upgrade native --- native | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native b/native index 74057385bf..618680d379 160000 --- a/native +++ b/native @@ -1 +1 @@ -Subproject commit 74057385bfc3baae81b3e35266596d031a196067 +Subproject commit 618680d3792980df42b29ab7bedec4a5f2a802b5 From 6b64554e64312dbec37fe837b00be08a922986e6 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 3 Jan 2013 12:46:10 +0100 Subject: [PATCH 71/89] Fix savestates under JIT --- Core/MIPS/ARM/JitCache.cpp | 6 +----- Core/MIPS/x86/Asm.cpp | 4 ++-- Core/MIPS/x86/Jit.cpp | 8 ++++++++ Core/MIPS/x86/JitCache.cpp | 6 +----- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Core/MIPS/ARM/JitCache.cpp b/Core/MIPS/ARM/JitCache.cpp index 5df0381fa1..68a5aa5d3c 100644 --- a/Core/MIPS/ARM/JitCache.cpp +++ b/Core/MIPS/ARM/JitCache.cpp @@ -362,12 +362,8 @@ void JitBlockCache::DestroyBlock(int block_num, bool invalidate) return; } b.invalid = true; -#ifdef JIT_UNLIMITED_ICACHE - Memory::Write_Opcode_JIT(b.originalAddress, b.originalFirstOpcode?b.originalFirstOpcode:JIT_ICACHE_INVALID_WORD); -#else - if ((int)Memory::ReadUnchecked_U32(b.originalAddress) == block_num) + if ((int)Memory::ReadUnchecked_U32(b.originalAddress) == (MIPS_EMUHACK_OPCODE | block_num)) Memory::WriteUnchecked_U32(b.originalFirstOpcode, b.originalAddress); -#endif UnlinkBlock(block_num); diff --git a/Core/MIPS/x86/Asm.cpp b/Core/MIPS/x86/Asm.cpp index 67a6611e64..c2d57b6017 100644 --- a/Core/MIPS/x86/Asm.cpp +++ b/Core/MIPS/x86/Asm.cpp @@ -62,7 +62,7 @@ void Jit() void ImHere() { - DEBUG_LOG(CPU, "I'm Here: %08x", currentMIPS->pc); + DEBUG_LOG(CPU, "JIT Here: %08x", currentMIPS->pc); } void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit) @@ -107,7 +107,7 @@ void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit) dispatcherNoCheck = GetCodePtr(); // Debug - //CALL(&ImHere); + // CALL(&ImHere); MOV(32, R(EAX), M(&mips->pc)); #ifdef _M_IX86 diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp index e79e624e2d..58b04562fc 100644 --- a/Core/MIPS/x86/Jit.cpp +++ b/Core/MIPS/x86/Jit.cpp @@ -88,6 +88,14 @@ const u8 *Jit::DoJit(u32 em_address, JitBlock *b) js.compiling = true; js.inDelaySlot = false; + // We add a check before the block, used when entering from a linked block. + b->checkedEntry = GetCodePtr(); + // Downcount flag check. The last block decremented downcounter, and the flag should still be available. + FixupBranch skip = J_CC(CC_NBE); + MOV(32, M(&mips_->pc), Imm32(js.blockStart)); + JMP(asm_.outerLoop, true); // downcount hit zero - go advance. + SetJumpTarget(skip); + b->normalEntry = GetCodePtr(); // TODO: this needs work diff --git a/Core/MIPS/x86/JitCache.cpp b/Core/MIPS/x86/JitCache.cpp index c710923972..cd3d60039b 100644 --- a/Core/MIPS/x86/JitCache.cpp +++ b/Core/MIPS/x86/JitCache.cpp @@ -347,12 +347,8 @@ void JitBlockCache::DestroyBlock(int block_num, bool invalidate) return; } b.invalid = true; -#ifdef JIT_UNLIMITED_ICACHE - Memory::Write_Opcode_JIT(b.originalAddress, b.originalFirstOpcode?b.originalFirstOpcode:JIT_ICACHE_INVALID_WORD); -#else - if (Memory::ReadUnchecked_U32(b.originalAddress) == (u32)block_num) + if ((int)Memory::ReadUnchecked_U32(b.originalAddress) == (MIPS_EMUHACK_OPCODE | block_num)) Memory::WriteUnchecked_U32(b.originalFirstOpcode, b.originalAddress); -#endif UnlinkBlock(block_num); From 59e52f4e5a8c8aae07547a2c608e9570417aca0b Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 3 Jan 2013 14:02:35 +0100 Subject: [PATCH 72/89] Make MsgDialog not put text outside the screen. --- Core/Dialog/PSPDialog.cpp | 2 +- Core/Util/PPGeDraw.cpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Core/Dialog/PSPDialog.cpp b/Core/Dialog/PSPDialog.cpp index 9750fb917d..183ce97f3c 100644 --- a/Core/Dialog/PSPDialog.cpp +++ b/Core/Dialog/PSPDialog.cpp @@ -50,7 +50,7 @@ void PSPDialog::EndDraw() void PSPDialog::DisplayMessage(std::string text) { - PPGeDrawText(text.c_str(), 480/2, 100, PPGE_ALIGN_CENTER, 0.5f, 0xFFFFFFFF); + PPGeDrawText(text.c_str(), 40, 30, PPGE_ALIGN_LEFT, 0.5f, 0xFFFFFFFF); } int PSPDialog::Shutdown() diff --git a/Core/Util/PPGeDraw.cpp b/Core/Util/PPGeDraw.cpp index bd8032dd0b..cbd3bce81f 100644 --- a/Core/Util/PPGeDraw.cpp +++ b/Core/Util/PPGeDraw.cpp @@ -238,18 +238,20 @@ static void PPGeMeasureText(const char *text, float scale, float *w, float *h) { const AtlasFont &atlasfont = *ppge_atlas.fonts[0]; unsigned char cval; float wacc = 0; + float maxw = 0; int lines = 1; while ((cval = *text++) != '\0') { if (cval < 32) continue; if (cval > 127) continue; if (cval == '\n') { + if (wacc > maxw) maxw = wacc; wacc = 0; lines++; } AtlasChar c = atlasfont.chars[cval - 32]; wacc += c.wx * scale; } - if (w) *w = wacc; + if (w) *w = maxw; if (h) *h = atlasfont.height * scale * lines; } @@ -278,6 +280,7 @@ void PPGeDrawText(const char *text, float x, float y, int align, float scale, u3 float sx = x; while ((cval = *text++) != '\0') { if (cval == '\n') { + // This is not correct when centering or right-justifying, need to set x depending on line width (tricky) y += atlasfont.height * scale; x = sx; continue; From 3847ea46a8146cb7933bfe66bae03430523b89e0 Mon Sep 17 00:00:00 2001 From: Arthur Blot Date: Thu, 3 Jan 2013 16:13:08 +0100 Subject: [PATCH 73/89] Better output for faked modules --- Core/HLE/sceKernelModule.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index d590dc36e8..c4895299d2 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -112,7 +112,8 @@ public: void GetQuickInfo(char *ptr, int size) { // ignore size - sprintf(ptr, "name=%s gp=%08x entry=%08x", + sprintf(ptr, "%sname=%s gp=%08x entry=%08x", + isFake ? "faked " : "", nm.name, nm.gp_value, nm.entry_addr); @@ -237,6 +238,9 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro *error_string = "Missing key"; delete [] newptr; module->isFake = true; + strncpy(module->nm.name, head->modname, 28); + module->nm.entry_addr = -1; + module->nm.gp_value = -1; return module; } else if (ret <= 0) @@ -303,6 +307,9 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro else modinfo = (PspModuleInfo *)Memory::GetPointer(reader.GetSegmentVaddr(0) + (reader.GetSegmentPaddr(0) & 0x7FFFFFFF) - reader.GetSegmentOffset(0)); + module->nm.gp_value = modinfo->gp; + strncpy(module->nm.name, modinfo->name, 28); + // Check for module blacklist - we don't allow games to load these modules from disc // as we have HLE implementations and the originals won't run in the emu because they // directly access hardware or for other reasons. @@ -314,6 +321,7 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro delete [] newptr; } module->isFake = true; + module->nm.entry_addr = -1; return module; } } @@ -343,9 +351,6 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro } } - module->nm.gp_value = modinfo->gp; - strncpy(module->nm.name, modinfo->name, 28); - INFO_LOG(LOADER,"Module %s: %08x %08x %08x", modinfo->name, modinfo->gp, modinfo->libent,modinfo->libstub); struct PspLibStubEntry From be91ad2f9c75b18d65a8014b122476ad9e7a8f21 Mon Sep 17 00:00:00 2001 From: Arthur Blot Date: Thu, 3 Jan 2013 16:14:16 +0100 Subject: [PATCH 74/89] Fixed $zr being non-zero after loading instruction --- Core/MIPS/ARM/CompLoadStore.cpp | 4 ++++ Core/MIPS/MIPSInt.cpp | 5 +++++ Core/MIPS/x86/CompLoadStore.cpp | 5 +++++ 3 files changed, 14 insertions(+) diff --git a/Core/MIPS/ARM/CompLoadStore.cpp b/Core/MIPS/ARM/CompLoadStore.cpp index 9db18b946c..e8d8430447 100644 --- a/Core/MIPS/ARM/CompLoadStore.cpp +++ b/Core/MIPS/ARM/CompLoadStore.cpp @@ -42,6 +42,10 @@ namespace MIPSComp int rt = _RT; int rs = _RS; int o = op>>26; + if (((op >> 29) & 1) == 0 && rt == 0) { + // Don't load anything into $zr + return; + } switch (o) { case 37: //R(rt) = ReadMem16(addr); break; //lhu diff --git a/Core/MIPS/MIPSInt.cpp b/Core/MIPS/MIPSInt.cpp index e97746cd58..7777d71c5a 100644 --- a/Core/MIPS/MIPSInt.cpp +++ b/Core/MIPS/MIPSInt.cpp @@ -398,6 +398,11 @@ namespace MIPSInt int rs = _RS; u32 addr = R(rs) + imm; + if (((op >> 29) & 1) == 0 && rt == 0) { + // Don't load anything into $zr + return; + } + switch (op >> 26) { case 32: R(rt) = (u32)(s32)(s8) Memory::Read_U8(addr); break; //lb diff --git a/Core/MIPS/x86/CompLoadStore.cpp b/Core/MIPS/x86/CompLoadStore.cpp index 631dc803aa..b262b11699 100644 --- a/Core/MIPS/x86/CompLoadStore.cpp +++ b/Core/MIPS/x86/CompLoadStore.cpp @@ -52,6 +52,11 @@ namespace MIPSComp int rt = _RT; int rs = _RS; int o = op>>26; + if (((op >> 29) & 1) == 0 && rt == 0) { + // Don't load anything into $zr + return; + } + switch (o) { case 37: //R(rt) = ReadMem16(addr); break; //lhu From decbf9da812074ea5f4d4a80a523d7cddfc394a0 Mon Sep 17 00:00:00 2001 From: Arthur Blot Date: Thu, 3 Jan 2013 17:01:12 +0100 Subject: [PATCH 75/89] Fixed interpreter --- Core/MIPS/MIPSInt.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Core/MIPS/MIPSInt.cpp b/Core/MIPS/MIPSInt.cpp index 7777d71c5a..c3bcfe4ab9 100644 --- a/Core/MIPS/MIPSInt.cpp +++ b/Core/MIPS/MIPSInt.cpp @@ -301,8 +301,10 @@ namespace MIPSInt int rt = _RT; int rs = _RS; - if (rt == 0) //destination register is zero register + if (rt == 0) { //destination register is zero register + PC += 4; return; //nop + } switch (op>>26) { @@ -400,6 +402,7 @@ namespace MIPSInt if (((op >> 29) & 1) == 0 && rt == 0) { // Don't load anything into $zr + PC += 4; return; } From a842c4620874c8a915219240e44fba89d830406b Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 3 Jan 2013 22:53:36 +0100 Subject: [PATCH 76/89] Some operations were doing things in 16-byte blocks. Adjust some buffer sizes to allow for this. Also remove a global. --- Core/ELF/PrxDecrypter.cpp | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/Core/ELF/PrxDecrypter.cpp b/Core/ELF/PrxDecrypter.cpp index 248d27f2b4..f9a643463b 100644 --- a/Core/ELF/PrxDecrypter.cpp +++ b/Core/ELF/PrxDecrypter.cpp @@ -8,6 +8,8 @@ extern "C" #include "../../Globals.h" #include "PrxDecrypter.h" +#define ROUNDUP16(x) (((x)+15)&~15) + // Thank you PSARDUMPER & JPCSP keys // PRXDecrypter 16-byte tag keys. @@ -314,21 +316,17 @@ static const TAG_INFO *GetTagInfo(u32 tagFind) static void ExtraV2Mangle(u8* buffer1, u8 codeExtra) { -#ifdef _MSC_VER - static u8 __declspec(align(64)) g_dataTmp[20+0xA0]; -#else - static u8 g_dataTmp[20+0xA0] __attribute__((aligned(0x40))); -#endif - u8* buffer2 = g_dataTmp; // aligned + u8 buffer2[ROUNDUP16(0x14+0xA0)]; + + memcpy(buffer2+0x14, buffer1, 0xA0); - memcpy(buffer2+20, buffer1, 0xA0); u32* pl2 = (u32*)buffer2; pl2[0] = 5; pl2[1] = pl2[2] = 0; pl2[3] = codeExtra; pl2[4] = 0xA0; - sceUtilsBufferCopyWithRange(buffer2, 20+0xA0, buffer2, 20+0xA0, 7); + sceUtilsBufferCopyWithRange(buffer2, 20+0xA0, buffer2, 20+0xA0, KIRK_CMD_DECRYPT_IV_0); // copy result back memcpy(buffer1, buffer2, 0xA0); } @@ -340,7 +338,7 @@ static int Scramble(u32 *buf, u32 size, u32 code) buf[3] = code; buf[4] = size; - if (sceUtilsBufferCopyWithRange((u8*)buf, size+0x14, (u8*)buf, size+0x14, 7) < 0) + if (sceUtilsBufferCopyWithRange((u8*)buf, size+0x14, (u8*)buf, size+0x14, KIRK_CMD_DECRYPT_IV_0) < 0) { return -1; } @@ -603,6 +601,7 @@ static const TAG_INFO2 *GetTagInfo2(u32 tagFind) return NULL; // not found } + static int DecryptPRX2(const u8 *inbuf, u8 *outbuf, u32 size, u32 tag) { const TAG_INFO2 *pti = GetTagInfo2(tag); @@ -616,13 +615,11 @@ static int DecryptPRX2(const u8 *inbuf, u8 *outbuf, u32 size, u32 tag) return MISSING_KEY; } - int retsize = *(int *)&inbuf[0xB0]; - u8 tmp1[0x150], tmp2[0x90+0x14], tmp3[0x90+0x14], tmp4[0x20]; - - memset(tmp1, 0, 0x150); - memset(tmp2, 0, 0x90+0x14); - memset(tmp3, 0, 0x90+0x14); - memset(tmp4, 0, 0x20); + int retsize = *(const int *)&inbuf[0xB0]; + u8 tmp1[0x150] = {0}; + u8 tmp2[ROUNDUP16(0x90+0x14)] = {0}; + u8 tmp3[ROUNDUP16(0x90+0x14)] = {0}; + u8 tmp4[ROUNDUP16(0x20)] = {0}; if (inbuf != outbuf) memcpy(outbuf, inbuf, size); @@ -640,15 +637,16 @@ static int DecryptPRX2(const u8 *inbuf, u8 *outbuf, u32 size, u32 tag) memcpy(tmp1, outbuf, 0x150); int i, j; - u8 *p = tmp2+0x14; + u8 *p = tmp2 + 0x14; + // Writes 0x90 bytes to tmp2 + 0x14. for (i = 0; i < 9; i++) { for (j = 0; j < 0x10; j++) { p[(i << 4) + j] = pti->key[j]; } - p[(i << 4)] = i; // really? + p[(i << 4)] = i; // really? this is very odd } if (Scramble((u32 *)tmp2, 0x90, pti->code) < 0) From cfc4717a511d2146c31f1afe44eaa169e69c1c16 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 4 Jan 2013 00:16:34 +0100 Subject: [PATCH 77/89] Ignore voicenum = -1 in sceSasSetKeyOff for now. Update native. --- Core/HLE/sceSas.cpp | 18 ++++++++++-------- native | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Core/HLE/sceSas.cpp b/Core/HLE/sceSas.cpp index 45693a80e5..b802088edb 100644 --- a/Core/HLE/sceSas.cpp +++ b/Core/HLE/sceSas.cpp @@ -226,17 +226,19 @@ u32 sceSasSetKeyOn(u32 core, int voiceNum) // sceSasSetKeyOff can be used to start sounds, that just sound during the Release phase! u32 sceSasSetKeyOff(u32 core, int voiceNum) { - DEBUG_LOG(HLE,"0=sceSasSetKeyOff(core=%08x, voiceNum=%i)", core, voiceNum); - - if (voiceNum >= PSP_SAS_VOICES_MAX || voiceNum < 0) - { + if (voiceNum == -1) { + // TODO: Some games (like Every Extend Extra) deliberately pass voiceNum = -1. Does that mean all voices? for now let's ignore. + DEBUG_LOG(HLE,"sceSasSetKeyOff(core=%08x, voiceNum=%i) - voiceNum = -1???", core, voiceNum); + return 0; + } else if (voiceNum < 0 || voiceNum >= PSP_SAS_VOICES_MAX) { WARN_LOG(HLE, "%s: invalid voicenum %d", __FUNCTION__, voiceNum); return ERROR_SAS_INVALID_VOICE; + } else { + DEBUG_LOG(HLE,"0=sceSasSetKeyOff(core=%08x, voiceNum=%i)", core, voiceNum); + SasVoice &v = sas->voices[voiceNum]; + v.KeyOff(); + return 0; } - - SasVoice &v = sas->voices[voiceNum]; - v.KeyOff(); - return 0; } u32 sceSasSetNoise(u32 core, int voiceNum, int freq) diff --git a/native b/native index 618680d379..dbda5f8037 160000 --- a/native +++ b/native @@ -1 +1 @@ -Subproject commit 618680d3792980df42b29ab7bedec4a5f2a802b5 +Subproject commit dbda5f8037e3da7fda5e5ec4cb59a8047c319e38 From 8f26e128bffed08444888733d57168d83d7a538e Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 4 Jan 2013 00:32:18 +0100 Subject: [PATCH 78/89] Ignore bogus invalidate cache calls, fixes slowdown in some games --- Core/HLE/sceKernel.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index e21876fd41..7aab757c54 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -241,24 +241,30 @@ void sceKernelGetGPI() // textures, and in the future display lists, in some cases though. int sceKernelDcacheInvalidateRange(u32 addr, int size) { - gpu->InvalidateCache(addr, size); + if (size > 0 && addr != 0) { + gpu->InvalidateCache(addr, size); + } return 0; } int sceKernelDcacheWritebackAll() { - // Some games seem to use this a lot, it doesn't make sense + // Some games seem to use this a lot, it doesn't make sense // to zap the whole texture cache. // gpu->InvalidateCache(0, -1); return 0; } int sceKernelDcacheWritebackRange(u32 addr, int size) { - gpu->InvalidateCache(addr, size); + if (size > 0 && addr != 0) { + gpu->InvalidateCache(addr, size); + } return 0; } int sceKernelDcacheWritebackInvalidateRange(u32 addr, int size) { - gpu->InvalidateCache(addr, size); + if (size > 0 && addr != 0) { + gpu->InvalidateCache(addr, size); + } return 0; } int sceKernelDcacheWritebackInvalidateAll() From a693081b17ab3a552722472e9d9d1288d88955b4 Mon Sep 17 00:00:00 2001 From: Arthur Blot Date: Fri, 4 Jan 2013 00:57:30 +0100 Subject: [PATCH 79/89] Fixed $k0 overwriting $sp content & stack address --- Core/HLE/sceKernelThread.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index cd7b4fbb4b..cda295560a 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -366,10 +366,10 @@ public: // Fill the stack. Memory::Memset(stackBlock, 0xFF, stackSize); context.r[MIPS_REG_SP] = stackBlock + stackSize; - nt.initialStack = context.r[MIPS_REG_SP]; + nt.initialStack = stackBlock; nt.stackSize = stackSize; // What's this 512? - context.r[MIPS_REG_K0] = context.r[MIPS_REG_SP] - 512; + context.r[MIPS_REG_K0] = context.r[MIPS_REG_SP] - 256; context.r[MIPS_REG_SP] -= 512; return true; } From 72446482dd9b8498ab6dc387f7b5c0d285318b1b Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 4 Jan 2013 09:04:27 +0100 Subject: [PATCH 80/89] Add some Hprm functions and a small logging tweak --- Core/HLE/sceHprm.cpp | 29 ++++++++++++++++++++++------- Core/HLE/scePower.cpp | 2 +- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/Core/HLE/sceHprm.cpp b/Core/HLE/sceHprm.cpp index 63490c960d..6d1d3196a6 100644 --- a/Core/HLE/sceHprm.cpp +++ b/Core/HLE/sceHprm.cpp @@ -20,29 +20,44 @@ #include "sceCtrl.h" -u32 sceHprmPeekCurrentKey(u32 keyAddress) -{ +u32 sceHprmPeekCurrentKey(u32 keyAddress) { INFO_LOG(HLE,"0=sceHprmPeekCurrentKey(ptr)"); Memory::Write_U32(0, keyAddress); return 0; } +// TODO: Might make sense to reflect the headphone status of the host here, +// if the games adjust their sound. +u32 sceHprmIsHeadphoneExist() { + DEBUG_LOG(HLE, "sceHprmIsHeadphoneExist()"); + return 0; +} + +u32 sceHprmIsMicrophoneExist() { + DEBUG_LOG(HLE, "sceHprmIsMicrophoneExist()"); + return 0; +} + +u32 sceHprmIsRemoteExist() { + DEBUG_LOG(HLE, "sceHprmIsRemoteExist()"); + return 0; +} + const HLEFunction sceHprm[] = { {0x089fdfa4, 0, "sceHprm_0x089fdfa4"}, {0x1910B327, &WrapU_U, "sceHprmPeekCurrentKey"}, - {0x208DB1BD, 0, "sceHprmIsRemoteExist"}, - {0x7E69EDA4, 0, "sceHprmIsHeadphoneExist"}, - {0x219C58F1, 0, "sceHprmIsMicrophoneExist"}, + {0x208DB1BD, WrapU_V, "sceHprmIsRemoteExist"}, + {0x7E69EDA4, WrapU_V, "sceHprmIsHeadphoneExist"}, + {0x219C58F1, WrapU_V, "sceHprmIsMicrophoneExist"}, {0xC7154136, 0, "sceHprmRegisterCallback"}, {0x444ED0B7, 0, "sceHprmUnregisterCallback"}, {0x1910B327, 0, "sceHprmPeekCurrentKey"}, {0x2BCEC83E, 0, "sceHprmPeekLatch"}, {0x40D2F9F0, 0, "sceHprmReadLatch"}, }; -const int sceHprmCount = ARRAY_SIZE(sceHprm); void Register_sceHprm() { - RegisterModule("sceHprm", sceHprmCount, sceHprm); + RegisterModule("sceHprm", ARRAY_SIZE(sceHprm), sceHprm); } diff --git a/Core/HLE/scePower.cpp b/Core/HLE/scePower.cpp index f486c064f9..13fbcaf85a 100644 --- a/Core/HLE/scePower.cpp +++ b/Core/HLE/scePower.cpp @@ -181,7 +181,7 @@ u32 scePowerSetBusClockFrequency(u32 busfreq) { u32 scePowerGetCpuClockFrequencyInt() { int freq = CoreTiming::GetClockFrequencyMHz(); - INFO_LOG(HLE,"%i=scePowerGetCpuClockFrequencyInt()", freq); + DEBUG_LOG(HLE,"%i=scePowerGetCpuClockFrequencyInt()", freq); return freq; } From f8ae18a1307b87c619bb2a1ddc618b924b738cb5 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 4 Jan 2013 09:54:19 +0100 Subject: [PATCH 81/89] "Fix" bezier the old way (puzzle bobble works again at least). --- GPU/GLES/DisplayListInterpreter.cpp | 2 +- GPU/GLES/TransformPipeline.cpp | 38 ++++++++++++++++------------- GPU/GLES/TransformPipeline.h | 2 +- GPU/GLES/VertexDecoder.cpp | 27 +++++++++++++++++--- GPU/GLES/VertexDecoder.h | 4 +++ 5 files changed, 50 insertions(+), 23 deletions(-) diff --git a/GPU/GLES/DisplayListInterpreter.cpp b/GPU/GLES/DisplayListInterpreter.cpp index 85e13abf12..761dab5fc4 100644 --- a/GPU/GLES/DisplayListInterpreter.cpp +++ b/GPU/GLES/DisplayListInterpreter.cpp @@ -484,7 +484,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { } int bytesRead; - transformDraw_.SubmitPrim(verts, inds, type, count, gstate.vertType, 0, -1, &bytesRead); + transformDraw_.SubmitPrim(verts, inds, type, count, gstate.vertType, -1, &bytesRead); // After drawing, we advance the vertexAddr (when non indexed) or indexAddr (when indexed). // Some games rely on this, they don't bother reloading VADDR and IADDR. // Q: Are these changed reflected in the real registers? Needs testing. diff --git a/GPU/GLES/TransformPipeline.cpp b/GPU/GLES/TransformPipeline.cpp index 82d548c4f8..e849032a94 100644 --- a/GPU/GLES/TransformPipeline.cpp +++ b/GPU/GLES/TransformPipeline.cpp @@ -64,8 +64,7 @@ TransformDrawEngine::~TransformDrawEngine() { void TransformDrawEngine::DrawBezier(int ucount, int vcount) { u16 indices[3 * 3 * 6]; - u32 customVertType = gstate.vertType; //(gstate.vertType & ~GE_VTYPE_TC_MASK) | GE_VTYPE_TC_FLOAT; - float customUV[32]; + // Generate indices for a rectangular mesh. int c = 0; for (int y = 0; y < 3; y++) { for (int x = 0; x < 3; x++) { @@ -78,6 +77,14 @@ void TransformDrawEngine::DrawBezier(int ucount, int vcount) { } } + // We are free to use the "decoded" buffer here. + // Let's split it into two to get a second buffer, there's enough space. + u8 *decoded2 = decoded + 65536 * 24; + + // Alright, now for the vertex data. + // For now, we will simply inject UVs. + + float customUV[4 * 4 * 2]; for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { customUV[(y * 4 + x) * 2 + 0] = (float)x/3.0f; @@ -85,8 +92,13 @@ void TransformDrawEngine::DrawBezier(int ucount, int vcount) { } } - int vertexCount = 3 * 3 * 6; - SubmitPrim(Memory::GetPointer(gstate_c.vertexAddr), &indices[0], GE_PRIM_TRIANGLES, vertexCount, customVertType, customUV, GE_VTYPE_IDX_16BIT, 0); + if (!(gstate.vertType & GE_VTYPE_TC_MASK)) { + dec.SetVertexType(gstate.vertType); + u32 newVertType = dec.InjectUVs(decoded2, Memory::GetPointer(gstate_c.vertexAddr), customUV, 16); + SubmitPrim(decoded2, &indices[0], GE_PRIM_TRIANGLES, c, newVertType, GE_VTYPE_IDX_16BIT, 0); + } else { + SubmitPrim(Memory::GetPointer(gstate_c.vertexAddr), &indices[0], GE_PRIM_TRIANGLES, c, gstate.vertType, GE_VTYPE_IDX_16BIT, 0); + } } void TransformDrawEngine::DrawSpline(int ucount, int vcount, int utype, int vtype) { @@ -330,18 +342,6 @@ static void RotateUVs(TransformedVertex v[4]) { // GL_TRIANGLES. Still need to sw transform to compute the extra two corners though. void TransformDrawEngine::SoftwareTransformAndDraw( int prim, u8 *decoded, LinkedShader *program, int vertexCount, u32 vertType, void *inds, int indexType, const DecVtxFormat &decVtxFormat, int maxIndex) { - /* - DEBUG_LOG(G3D, "View matrix:"); - const float *m = &gstate.viewMatrix[0]; - DEBUG_LOG(G3D, "%f %f %f", m[0], m[1], m[2]); - DEBUG_LOG(G3D, "%f %f %f", m[3], m[4], m[5]); - DEBUG_LOG(G3D, "%f %f %f", m[6], m[7], m[8]); - DEBUG_LOG(G3D, "%f %f %f", m[9], m[10], m[11]); - */ - - // Temporary storage for RECTANGLES emulation - float v2[3] = {0}; - float uv2[2] = {0}; bool throughmode = (vertType & GE_VTYPE_THROUGH_MASK) != 0; @@ -541,6 +541,10 @@ void TransformDrawEngine::SoftwareTransformAndDraw( numTrans = vertexCount; drawIndexed = true; } else { + // Temporary storage for RECTANGLES emulation + float v2[3] = {0}; + float uv2[2] = {0}; + numTrans = 0; drawBuffer = transformedExpanded; TransformedVertex *trans = &transformedExpanded[0]; @@ -615,7 +619,7 @@ void TransformDrawEngine::SoftwareTransformAndDraw( if (program->a_color1 != -1) glDisableVertexAttribArray(program->a_color1); } -void TransformDrawEngine::SubmitPrim(void *verts, void *inds, int prim, int vertexCount, u32 vertType, float *customUV, int forceIndexType, int *bytesRead) { +void TransformDrawEngine::SubmitPrim(void *verts, void *inds, int prim, int vertexCount, u32 vertType, int forceIndexType, int *bytesRead) { // For the future if (!indexGen.PrimCompatible(prim)) Flush(); diff --git a/GPU/GLES/TransformPipeline.h b/GPU/GLES/TransformPipeline.h index 3be12aaa1c..829c3152b6 100644 --- a/GPU/GLES/TransformPipeline.h +++ b/GPU/GLES/TransformPipeline.h @@ -29,7 +29,7 @@ class TransformDrawEngine { public: TransformDrawEngine(); ~TransformDrawEngine(); - void SubmitPrim(void *verts, void *inds, int prim, int vertexCount, u32 vertexType, float *customUV, int forceIndexType, int *bytesRead); + void SubmitPrim(void *verts, void *inds, int prim, int vertexCount, u32 vertexType, int forceIndexType, int *bytesRead); void DrawBezier(int ucount, int vcount); void DrawSpline(int ucount, int vcount, int utype, int vtype); void Flush(); diff --git a/GPU/GLES/VertexDecoder.cpp b/GPU/GLES/VertexDecoder.cpp index 3a3ffe650c..100640c424 100644 --- a/GPU/GLES/VertexDecoder.cpp +++ b/GPU/GLES/VertexDecoder.cpp @@ -645,8 +645,7 @@ void VertexDecoder::SetVertexType(u32 fmt) { DEBUG_LOG(G3D,"SVT : size = %i, aligned to biggest %i", size, biggest); } -void VertexDecoder::DecodeVerts(u8 *decodedptr, const void *verts, const void *inds, int prim, int count, int *indexLowerBound, int *indexUpperBound) const -{ +void VertexDecoder::DecodeVerts(u8 *decodedptr, const void *verts, const void *inds, int prim, int count, int *indexLowerBound, int *indexUpperBound) const { // Find index bounds. Could cache this in display lists. // Also, this could be greatly sped up with SSE2, although rarely a bottleneck. int lowerBound = 0x7FFFFFFF; @@ -677,8 +676,7 @@ void VertexDecoder::DecodeVerts(u8 *decodedptr, const void *verts, const void *i // Decode the vertices within the found bounds, once each decoded_ = decodedptr; // + lowerBound * decFmt.stride; ptr_ = (const u8*)verts + lowerBound * size; - for (int index = lowerBound; index <= upperBound; index++) - { + for (int index = lowerBound; index <= upperBound; index++) { for (int i = 0; i < numSteps_; i++) { ((*this).*steps_[i])(); } @@ -686,3 +684,24 @@ void VertexDecoder::DecodeVerts(u8 *decodedptr, const void *verts, const void *i decoded_ += decFmt.stride; } } + +// TODO: Does not support morphs, skinning etc. +u32 VertexDecoder::InjectUVs(u8 *decoded, const void *verts, float *customuv, int count) const { + u32 customVertType = (gstate.vertType & ~GE_VTYPE_TC_MASK) | GE_VTYPE_TC_FLOAT; + VertexDecoder decOut; + decOut.SetVertexType(customVertType); + + const u8 *inp = (const u8 *)verts; + u8 *out = decoded; + for (int i = 0; i < count; i++) { + if (pos) memcpy(out + decOut.posoff, inp + posoff, possize[pos]); + if (nrm) memcpy(out + decOut.nrmoff, inp + nrmoff, nrmsize[pos]); + if (col) memcpy(out + decOut.coloff, inp + coloff, colsize[pos]); + // Ignore others for now, this is all we need for puzbob. + // Inject! + memcpy(out + decOut.tcoff, &customuv[i * 2], tcsize[decOut.tc]); + inp += this->onesize_; + out += decOut.onesize_; + } + return customVertType; +} diff --git a/GPU/GLES/VertexDecoder.h b/GPU/GLES/VertexDecoder.h index 406b668428..771e1e35a7 100644 --- a/GPU/GLES/VertexDecoder.h +++ b/GPU/GLES/VertexDecoder.h @@ -88,6 +88,10 @@ public: const DecVtxFormat &GetDecVtxFmt() { return decFmt; } void DecodeVerts(u8 *decoded, const void *verts, const void *inds, int prim, int count, int *indexLowerBound, int *indexUpperBound) const; + + // This could be easily generalized to inject any one component. Don't know another use for it though. + u32 InjectUVs(u8 *decoded, const void *verts, float *customuv, int count) const; + bool hasColor() const { return col != 0; } int VertexSize() const { return size; } From a9c171c786761dcb77c9cb1fbcfbe4ba0d0d8f29 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 4 Jan 2013 10:26:14 +0100 Subject: [PATCH 82/89] Fix bAutoRun config option, add to menu. (Run on Load). --- Core/Config.cpp | 26 +++-- Core/Config.h | 2 +- Core/Core.cpp | 5 +- Core/FileSystems/ISOFileSystem.cpp | 2 +- Windows/EmuThread.cpp | 17 +-- Windows/PPSSPP.vcxproj | 10 +- Windows/WndMainWindow.cpp | 5 + Windows/main.cpp | 9 +- Windows/ppsspp.rc | 159 ++++++++++++----------------- Windows/resource.h | 3 +- android/jni/EmuScreen.cpp | 2 - 11 files changed, 112 insertions(+), 128 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 113860c86a..be380fc925 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -33,18 +33,21 @@ CConfig::~CConfig() void CConfig::Load(const char *iniFileName) { iniFilename_ = iniFileName; - NOTICE_LOG(LOADER, "Loading config: %s", iniFileName); + INFO_LOG(LOADER, "Loading config: %s", iniFileName); bSaveSettings = true; IniFile iniFile; - iniFile.Load(iniFileName); + if (!iniFile.Load(iniFileName)) { + ERROR_LOG(LOADER, "Failed to read %s. Setting config to default.", iniFileName); + // Continue anyway to initialize the config. + } IniFile::Section *general = iniFile.GetOrCreateSection("General"); bSpeedLimit = false; general->Get("FirstRun", &bFirstRun, true); general->Get("AutoLoadLast", &bAutoLoadLast, false); - general->Get("AutoRun", &bAutoRun, false); + general->Get("AutoRun", &bAutoRun, true); general->Get("ConfirmOnQuit", &bConfirmOnQuit, false); general->Get("IgnoreBadMemAccess", &bIgnoreBadMemAccess, true); general->Get("CurrentDirectory", ¤tDirectory, ""); @@ -75,10 +78,12 @@ void CConfig::Load(const char *iniFileName) void CConfig::Save() { - if (g_Config.bSaveSettings && iniFilename_.size()) - { + if (iniFilename_.size() && g_Config.bSaveSettings) { IniFile iniFile; - iniFile.Load(iniFilename_.c_str()); + if (!iniFile.Load(iniFilename_.c_str())) { + ERROR_LOG(LOADER, "Error saving config - can't read ini %s", iniFilename_.c_str()); + return; + } IniFile::Section *general = iniFile.GetOrCreateSection("General"); general->Set("FirstRun", bFirstRun); @@ -107,9 +112,12 @@ void CConfig::Save() control->Set("ShowStick", bShowAnalogStick); control->Set("ShowTouchControls", bShowTouchControls); - iniFile.Save(iniFilename_.c_str()); - NOTICE_LOG(LOADER, "Config saved: %s", iniFilename_.c_str()); + if (!iniFile.Save(iniFilename_.c_str())) { + ERROR_LOG(LOADER, "Error saving config - can't write ini %s", iniFilename_.c_str()); + return; + } + INFO_LOG(LOADER, "Config saved: %s", iniFilename_.c_str()); } else { - NOTICE_LOG(LOADER, "Error saving config: %s", iniFilename_.c_str()); + INFO_LOG(LOADER, "Not saving config"); } } diff --git a/Core/Config.h b/Core/Config.h index 030d3ea8c1..2bfbfe1ea7 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -38,9 +38,9 @@ public: // These are broken bool bAutoLoadLast; bool bFirstRun; - bool bAutoRun; bool bSpeedLimit; bool bConfirmOnQuit; + bool bAutoRun; // start immediately // Core bool bIgnoreBadMemAccess; diff --git a/Core/Core.cpp b/Core/Core.cpp index 33124240f6..a94e5f8d7c 100644 --- a/Core/Core.cpp +++ b/Core/Core.cpp @@ -88,7 +88,7 @@ void Core_Run() while (true) { reswitch: - switch(coreState) + switch (coreState) { case CORE_RUNNING: //1: enter a fast runloop @@ -132,7 +132,7 @@ void Core_EnableStepping(bool step) #if defined(_DEBUG) host->SetDebugMode(true); #endif - coreState=CORE_STEPPING; + coreState = CORE_STEPPING; } else { @@ -145,5 +145,4 @@ void Core_EnableStepping(bool step) m_hStepEvent.notify_one(); } - } diff --git a/Core/FileSystems/ISOFileSystem.cpp b/Core/FileSystems/ISOFileSystem.cpp index c526be4c15..a8ea984e43 100644 --- a/Core/FileSystems/ISOFileSystem.cpp +++ b/Core/FileSystems/ISOFileSystem.cpp @@ -209,7 +209,7 @@ nextblock: if (strlen(name) == 1 && name[0] == '\x01') // ".." record { strcpy(name,".."); - relative=true; + relative = true; } TreeEntry *e = new TreeEntry; diff --git a/Windows/EmuThread.cpp b/Windows/EmuThread.cpp index f6795df085..b03761a956 100644 --- a/Windows/EmuThread.cpp +++ b/Windows/EmuThread.cpp @@ -78,6 +78,7 @@ DWORD TheThread(LPVOID x) coreParameter.outputHeight = 272 * g_Config.iWindowZoom; coreParameter.pixelWidth = 480 * g_Config.iWindowZoom; coreParameter.pixelHeight = 272 * g_Config.iWindowZoom; + coreParameter.startPaused = !g_Config.bAutoRun; std::string error_string; if (!PSP_Init(coreParameter, &error_string)) @@ -89,20 +90,8 @@ DWORD TheThread(LPVOID x) INFO_LOG(BOOT, "Done."); _dbg_update_(); - if (g_Config.bAutoRun) - { -#ifdef _DEBUG - host->UpdateDisassembly(); -#endif - Core_EnableStepping(FALSE); - } - else - { -#ifdef _DEBUG - host->UpdateDisassembly(); -#endif - Core_EnableStepping(TRUE); - } + host->UpdateDisassembly(); + Core_EnableStepping(coreParameter.startPaused ? TRUE : FALSE); g_State.bBooted = true; #ifdef _DEBUG diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj index 4d14a6d2e3..bd233cf1af 100644 --- a/Windows/PPSSPP.vcxproj +++ b/Windows/PPSSPP.vcxproj @@ -112,9 +112,10 @@ Windows MachineX86 $(OutDir)$(TargetName)$(TargetExt) - true + false true 0x00400000 + true @@ -139,7 +140,7 @@ $(OutDir)$(ProjectName).pdb Windows MachineX64 - true + false true 0x00400000 @@ -175,6 +176,11 @@ MachineX86 /ignore:4049 %(AdditionalOptions) UseLinkTimeCodeGeneration + 0x00400000 + false + true + true + true diff --git a/Windows/WndMainWindow.cpp b/Windows/WndMainWindow.cpp index 58a86caea6..49f3531953 100644 --- a/Windows/WndMainWindow.cpp +++ b/Windows/WndMainWindow.cpp @@ -421,6 +421,10 @@ namespace MainWindow UpdateMenus(); break; + case ID_EMULATION_RUNONLOAD: + g_Config.bAutoRun = !g_Config.bAutoRun; + UpdateMenus(); + break; //case ID_CPU_RESET: // MessageBox(hwndMain,"Use the controls in the disasm window for now..","Sorry",0); // Update(); @@ -700,6 +704,7 @@ namespace MainWindow CHECKITEM(ID_OPTIONS_HARDWARETRANSFORM, g_Config.bHardwareTransform); CHECKITEM(ID_OPTIONS_FASTMEMORY, g_Config.bFastMemory); CHECKITEM(ID_OPTIONS_LINEARFILTERING, g_Config.bLinearFiltering); + CHECKITEM(ID_EMULATION_RUNONLOAD, g_Config.bAutoRun); UINT enable = !Core_IsStepping() ? MF_GRAYED : MF_ENABLED; EnableMenuItem(menu,ID_EMULATION_RUN, g_State.bEmuThreadStarted ? enable : MF_GRAYED); diff --git a/Windows/main.cpp b/Windows/main.cpp index 75d1ec9e92..8bc5bb5260 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -56,7 +56,6 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin const char *fileToLog = NULL; const char *stateToLoad = NULL; bool hideLog = true; - bool autoRun = true; #ifdef _DEBUG hideLog = false; @@ -77,18 +76,22 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin { case 'j': g_Config.iCpuCore = CPU_JIT; + g_Config.bSaveSettings = false; break; case 'i': g_Config.iCpuCore = CPU_INTERPRETER; + g_Config.bSaveSettings = false; break; case 'f': g_Config.iCpuCore = CPU_FASTINTERPRETER; + g_Config.bSaveSettings = false; break; case 'l': hideLog = false; break; case 's': - autoRun = false; + g_Config.bAutoRun = false; + g_Config.bSaveSettings = false; break; case '-': if (!strcmp(__argv[i], "--log") && i < __argc - 1) @@ -162,8 +165,6 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin else MainWindow::BrowseAndBoot(); - if (autoRun) - MainWindow::SetNextState(CORE_RUNNING); if (fileToStart != NULL && stateToLoad != NULL) SaveState::Load(stateToLoad); diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 8fccc169a5..429d99b19b 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -167,6 +167,42 @@ IDI_STOPDISABLE ICON "stop1.ico" LANGUAGE LANG_NEUTRAL, SUBLANG_DEFAULT #pragma code_page(1252) +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONTROLS DIALOGEX 0, 0, 287, 238 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Controls" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,176,217,50,14 + PUSHBUTTON "Cancel",IDCANCEL,230,217,50,14 + LTEXT "NOTE: Currently controls are NOT configurable.",IDC_STATIC,7,7,188,10 + LISTBOX IDC_LISTCONTROLS,7,19,273,184,LBS_SORT | LBS_USETABSTOPS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CONTROLS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 280 + TOPMARGIN, 7 + BOTTOMMARGIN, 231 + END +END +#endif // APSTUDIO_INVOKED + + ///////////////////////////////////////////////////////////////////////////// // // Menu @@ -193,6 +229,8 @@ BEGIN MENUITEM SEPARATOR MENUITEM "R&eset", ID_EMULATION_RESET MENUITEM SEPARATOR + MENUITEM "&Run on load", ID_EMULATION_RUNONLOAD + MENUITEM SEPARATOR MENUITEM "&Interpreter", ID_CPU_INTERPRETER MENUITEM "&Slightly Faster Interpreter", ID_CPU_FASTINTERPRETER MENUITEM "&Dynarec", ID_CPU_DYNAREC, CHECKED @@ -236,92 +274,6 @@ BEGIN END END -#endif // Neutral (Default) resources -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUD) -LANGUAGE LANG_NEUTRAL, SUBLANG_DEFAULT -#pragma code_page(1252) -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_CONTROLS DIALOGEX 0, 0, 287, 238 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Controls" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - DEFPUSHBUTTON "OK",IDOK,176,217,50,14 - PUSHBUTTON "Cancel",IDCANCEL,230,217,50,14 - LTEXT "NOTE: Currently controls are NOT configurable.",IDC_STATIC,7,7,188,10 - LISTBOX IDC_LISTCONTROLS,7,19,273,184,LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_USETABSTOPS | WS_VSCROLL | WS_TABSTOP -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_CONTROLS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 280 - TOPMARGIN, 7 - BOTTOMMARGIN, 231 - END -END -#endif // APSTUDIO_INVOKED - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// Neutral resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUD) -LANGUAGE LANG_NEUTRAL, SUBLANG_DEFAULT -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Menu -// - IDR_POPUPMENUS MENU BEGIN POPUP "memview" @@ -363,6 +315,31 @@ BEGIN END +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + ///////////////////////////////////////////////////////////////////////////// // // RT_MANIFEST @@ -421,15 +398,15 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "Comments", "PPSSPP PSP emulator" - VALUE "CompanyName", "Henrik RydgÃ¥rd Inc." + VALUE "CompanyName", "Henrik Rydgård Inc." VALUE "FileDescription", "PPSSPP" - VALUE "FileVersion", "1, 0, 0, 0" + VALUE "FileVersion", "1, 0, 5, 0" VALUE "InternalName", "s" - VALUE "LegalCopyright", "Copyright (C) 2006-2012 by Henrik RydgÃ¥rd" + VALUE "LegalCopyright", "Copyright (C) 2006-2012 by Henrik Rydgård" VALUE "LegalTrademarks", "All product names are trademarks of their respective owners." VALUE "OriginalFilename", "PPSSPP.exe" VALUE "ProductName", "PPSSPP" - VALUE "ProductVersion", "1, 0, 0, 0" + VALUE "ProductVersion", "1, 0, 5, 0" END END BLOCK "VarFileInfo" @@ -457,7 +434,7 @@ BEGIN IDS_GAMELISTTYPE "Type" END -#endif // Neutral resources +#endif // Neutral (Default) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/Windows/resource.h b/Windows/resource.h index 57c1cb4c7d..83c39ed5be 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -253,6 +253,7 @@ #define ID_FILE_QUICKSAVESTATE 40128 #define ID_FILE_QUICKLOADSTATE 40129 #define ID_OPTIONS_CONTROLS 40130 +#define ID_EMULATION_RUNONLOAD 40131 #define IDC_STATIC -1 // Next default values for new objects @@ -260,7 +261,7 @@ #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 233 -#define _APS_NEXT_COMMAND_VALUE 40131 +#define _APS_NEXT_COMMAND_VALUE 40132 #define _APS_NEXT_CONTROL_VALUE 1163 #define _APS_NEXT_SYMED_VALUE 101 #endif diff --git a/android/jni/EmuScreen.cpp b/android/jni/EmuScreen.cpp index 9b02a97bd9..096d80d163 100644 --- a/android/jni/EmuScreen.cpp +++ b/android/jni/EmuScreen.cpp @@ -67,7 +67,6 @@ EmuScreen::EmuScreen(const std::string &filename) : invalid_(true) coreParam.outputHeight = dp_yres; coreParam.pixelWidth = pixel_xres; coreParam.pixelHeight = pixel_yres; - std::string error_string; if (PSP_Init(coreParam, &error_string)) { invalid_ = false; @@ -81,7 +80,6 @@ EmuScreen::EmuScreen(const std::string &filename) : invalid_(true) LayoutGamepad(dp_xres, dp_yres); NOTICE_LOG(BOOT, "Loading %s...", fileToStart.c_str()); - coreState = CORE_RUNNING; } EmuScreen::~EmuScreen() From 5066df58814d6a2d3cb44e9156f953527f9ffe8f Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 4 Jan 2013 14:33:24 +0100 Subject: [PATCH 83/89] 0.5 --- Windows/WindowsHost.cpp | 2 +- Windows/WndMainWindow.cpp | 2 +- Windows/ppsspp.rc | 10 +++++----- android/AndroidManifest.xml | 4 ++-- android/jni/MenuScreens.cpp | 7 ++++--- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index 7dc6b109ee..f82d722f9a 100644 --- a/Windows/WindowsHost.cpp +++ b/Windows/WindowsHost.cpp @@ -38,7 +38,7 @@ void WindowsHost::ShutdownGL() void WindowsHost::SetWindowTitle(const char *message) { // Really need a better way to deal with versions. - std::string title = "PPSSPP v0.4 - "; + std::string title = "PPSSPP v0.5 - "; title += message; int size = MultiByteToWideChar(CP_UTF8, 0, message, title.size(), NULL, 0); diff --git a/Windows/WndMainWindow.cpp b/Windows/WndMainWindow.cpp index 49f3531953..76dcd65786 100644 --- a/Windows/WndMainWindow.cpp +++ b/Windows/WndMainWindow.cpp @@ -1,7 +1,7 @@ // NOTE: Apologies for the quality of this code, this is really from pre-opensource Dolphin - that is, 2003. -#define programname "PPSSPP v0.4" +#define programname "PPSSPP v0.5" #include diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 429d99b19b..6b535444c5 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -45,10 +45,10 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPT CAPTION "About" FONT 8, "MS Shell Dlg", 0, 0, 0x0 BEGIN - DEFPUSHBUTTON "OK",IDOK,243,141,50,14 - ICON IDI_PPSSPP,IDC_STATIC,10,9,20,20 - LTEXT "PPSSPP",IDC_STATIC,40,8,127,9 - LTEXT "Copyright (c) by Henrik RydgÃ¥rd 2012",IDC_STATIC,40,33,253,8 + DEFPUSHBUTTON "OK",IDOK,243,140,50,14 + ICON IDI_PPSSPP,IDC_STATIC,10,9,21,20 + LTEXT "PPSSPP v0.5",IDC_STATIC,40,8,127,9 + LTEXT "Copyright (c) by Henrik Rydgård && the PPSSPP project 2012-",IDC_STATIC,40,33,253,8 LTEXT "All trademarks are property of their respective owners.\nThe emulator is for educational and development purposes only and it may not be used to play games you do not legally own.",IDC_STATIC,40,102,253,24 LTEXT "PSP emulator and debugger",IDC_STATIC,40,19,253,8 LTEXT "CISO decompression code by BOOSTER",IDC_STATIC,48,73,240,8 @@ -120,7 +120,7 @@ BEGIN VERTGUIDE, 48 VERTGUIDE, 280 TOPMARGIN, 7 - BOTTOMMARGIN, 155 + BOTTOMMARGIN, 154 END IDD_MEMORY, DIALOG diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 719be33b5a..9f3ce7a4e4 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="5" + android:versionName="0.5" > diff --git a/android/jni/MenuScreens.cpp b/android/jni/MenuScreens.cpp index c0316b32c8..da8ca19ddc 100644 --- a/android/jni/MenuScreens.cpp +++ b/android/jni/MenuScreens.cpp @@ -157,7 +157,7 @@ void MenuScreen::render() { ui_draw2d.DrawTextShadow(UBUNTU48, "PPSSPP", dp_xres + xoff - w/2, 80, 0xFFFFFFFF, ALIGN_HCENTER | ALIGN_BOTTOM); ui_draw2d.SetFontScale(0.7f, 0.7f); - ui_draw2d.DrawTextShadow(UBUNTU24, "V0.4", dp_xres + xoff, 80, 0xFFFFFFFF, ALIGN_RIGHT | ALIGN_BOTTOM); + ui_draw2d.DrawTextShadow(UBUNTU24, "v0.5", dp_xres + xoff, 80, 0xFFFFFFFF, ALIGN_RIGHT | ALIGN_BOTTOM); ui_draw2d.SetFontScale(1.0f, 1.0f); VLinear vlinear(dp_xres + xoff, 95, 20); @@ -247,7 +247,8 @@ void InGameMenuScreen::render() { if (UIButton(GEN_ID, vlinear, LARGE_BUTTON_WIDTH, "Return to Menu", ALIGN_RIGHT)) { screenManager()->finishDialog(this, DR_OK); } - if (UIButton(GEN_ID, vlinear, LARGE_BUTTON_WIDTH, "Dump Next Frame", ALIGN_RIGHT)) { + + if (UIButton(GEN_ID, Pos(dp_xres - 10, dp_yres - 10), LARGE_BUTTON_WIDTH*2, "Debug: Dump Next Frame", ALIGN_BOTTOMRIGHT)) { gpu->DumpNextFrame(); } @@ -404,7 +405,7 @@ void CreditsScreen::update(InputState &input_state) { static const char *credits[] = { - "PPSSPP v0.4", + "PPSSPP v0.5", "", "", "A fast and portable PSP emulator", From f8f62483f0969354994a59bcee308f5633b32047 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 4 Jan 2013 16:11:51 +0100 Subject: [PATCH 84/89] Fix silly mistake with config saving. --- Core/Config.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index be380fc925..bc68d1ba5f 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -82,7 +82,6 @@ void CConfig::Save() IniFile iniFile; if (!iniFile.Load(iniFilename_.c_str())) { ERROR_LOG(LOADER, "Error saving config - can't read ini %s", iniFilename_.c_str()); - return; } IniFile::Section *general = iniFile.GetOrCreateSection("General"); From 10ec424787b5514de4976b1c386a2d9f731fc461 Mon Sep 17 00:00:00 2001 From: Arthur Blot Date: Fri, 4 Jan 2013 16:45:31 +0100 Subject: [PATCH 85/89] Fixed PPSSPPSDL path in test.py for linux --- test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.py b/test.py index 9fb54bcb1c..557ce0202a 100755 --- a/test.py +++ b/test.py @@ -8,7 +8,7 @@ import subprocess import threading -PPSSPP_EXECUTABLES = [ "Windows\\Release\\PPSSPPHeadless.exe", "SDL/build/PPSSPPHeadless" ] +PPSSPP_EXECUTABLES = [ "Windows\\Release\\PPSSPPHeadless.exe", "build/PPSSPPHeadless" ] PPSSPP_EXE = None TEST_ROOT = "pspautotests/tests/" teamcity_mode = False From b12bc54ddaa6eb0f446fecbe1fbd2162b913a865 Mon Sep 17 00:00:00 2001 From: Arthur Blot Date: Fri, 4 Jan 2013 17:06:36 +0100 Subject: [PATCH 86/89] Fixed threads/k0 test, updated pspautotests --- Core/HLE/sceKernelThread.cpp | 8 ++++++++ pspautotests | 2 +- test.py | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index cda295560a..399417a050 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -371,6 +371,14 @@ public: // What's this 512? context.r[MIPS_REG_K0] = context.r[MIPS_REG_SP] - 256; context.r[MIPS_REG_SP] -= 512; + u32 k0 = context.r[MIPS_REG_K0]; + Memory::Memset(k0, 0, 0x100); + Memory::Write_U32(nt.initialStack, k0 + 0xc0); + Memory::Write_U32(GetUID(), k0 + 0xca); + Memory::Write_U32(0xffffffff, k0 + 0xf8); + Memory::Write_U32(0xffffffff, k0 + 0xfc); + + Memory::Write_U32(GetUID(), nt.initialStack); return true; } diff --git a/pspautotests b/pspautotests index 3f1dc654e6..a35333fa37 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit 3f1dc654e66c37098169881e7d6437db3157dff8 +Subproject commit a35333fa37a6439ef6623fad7b66f19115ccf724 diff --git a/test.py b/test.py index 557ce0202a..306f9e442d 100755 --- a/test.py +++ b/test.py @@ -74,6 +74,7 @@ tests_good = [ "threads/events/refer/refer", "threads/events/set/set", "threads/events/wait/wait", + "threads/k0/k0", "threads/lwmutex/create/create", "threads/lwmutex/delete/delete", "threads/lwmutex/lock/lock", From 062b2320a28452e345570a6245f5f35f12204f83 Mon Sep 17 00:00:00 2001 From: Arthur Blot Date: Fri, 4 Jan 2013 20:09:39 +0100 Subject: [PATCH 87/89] Load ELFs at the correct place --- Core/ELF/ElfReader.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Core/ELF/ElfReader.cpp b/Core/ELF/ElfReader.cpp index 3ead77cf28..77ff90de4d 100644 --- a/Core/ELF/ElfReader.cpp +++ b/Core/ELF/ElfReader.cpp @@ -201,10 +201,21 @@ bool ElfReader::LoadInto(u32 loadAddress) } } u32 totalSize = totalEnd - totalStart; - if (loadAddress) - vaddr = userMemory.AllocAt(loadAddress, totalSize, "ELF"); + if (!bRelocate) + { + // Binary is prerelocated, load it where the first segment starts + vaddr = userMemory.AllocAt(totalStart, totalSize, "ELF"); + } + else if (loadAddress) + { + // Binary needs to be relocated: add loadAddress to the binary start address + vaddr = userMemory.AllocAt(loadAddress + totalStart, totalSize, "ELF"); + } else + { + // Just put it where there is room vaddr = userMemory.Alloc(totalSize, false, "ELF"); + } if (vaddr == -1) { ERROR_LOG(LOADER, "Failed to allocate memory for ELF!"); From 88296468e46f99f4b2b7b855bc9261b09ea51258 Mon Sep 17 00:00:00 2001 From: Xele02 Date: Sat, 5 Jan 2013 00:32:07 +0100 Subject: [PATCH 88/89] Some save are smaller than the buffer. This correct K-on Houkago Live Game which should check save size returned. --- Core/Dialog/SavedataParam.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index 84596e16eb..a3206736da 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -45,7 +45,7 @@ namespace str[strLength - 1] = 0; } - bool ReadPSPFile(std::string filename, u8 *data, s64 dataSize) + bool ReadPSPFile(std::string filename, u8 *data, s64 dataSize, s64 *readSize) { u32 handle = pspFileSystem.OpenFile(filename, FILEACCESS_READ); if (handle == 0) @@ -53,6 +53,8 @@ namespace int result = pspFileSystem.ReadFile(handle, data, dataSize); pspFileSystem.CloseFile(handle); + if(readSize) + *readSize = result; return result != 0; } @@ -210,10 +212,13 @@ bool SavedataParam::Save(SceUtilitySavedataParam* param, int saveId) if(param->dataBuf != 0) // Can launch save without save data in mode 13 { std::string filePath = dirPath+"/"+GetFileName(param); - INFO_LOG(HLE,"Saving file with size %u in %s",param->dataBufSize,filePath.c_str()); + int saveSize = param->dataSize; + if(saveSize == 0 || saveSize > param->dataBufSize) + saveSize = param->dataBufSize; // fallback, should never use this + INFO_LOG(HLE,"Saving file with size %u in %s",saveSize,filePath.c_str()); u8 *data_ = (u8*)Memory::GetPointer(param->dataBuf); - if (!WritePSPFile(filePath, data_, param->dataBufSize)) + if (!WritePSPFile(filePath, data_, saveSize)) { ERROR_LOG(HLE,"Error writing file %s",filePath.c_str()); return false; @@ -228,7 +233,7 @@ bool SavedataParam::Save(SceUtilitySavedataParam* param, int saveId) { u8 *sfoData = new u8[(size_t)sfoInfo.size]; size_t sfoSize = (size_t)sfoInfo.size; - if(ReadPSPFile(sfopath,sfoData,sfoSize)) + if(ReadPSPFile(sfopath,sfoData,sfoSize, NULL)) { sfoFile.ReadSFO(sfoData,sfoSize); delete[] sfoData; @@ -352,13 +357,14 @@ bool SavedataParam::Load(SceUtilitySavedataParam *param, int saveId) } std::string filePath = dirPath+"/"+GetFileName(param); + s64 readSize; INFO_LOG(HLE,"Loading file with size %u in %s",param->dataBufSize,filePath.c_str()); - if (!ReadPSPFile(filePath, data_, param->dataBufSize)) + if (!ReadPSPFile(filePath, data_, param->dataBufSize, &readSize)) { ERROR_LOG(HLE,"Error reading file %s",filePath.c_str()); return false; } - param->dataSize = param->dataBufSize; + param->dataSize = readSize; return true; } @@ -701,7 +707,7 @@ void SavedataParam::SetFileInfo(int idx, PSPFileInfo &info, std::string saveName if (info2.exists) { u8 *textureDataPNG = new u8[(size_t)info2.size]; - ReadPSPFile(fileDataPath2, textureDataPNG, info2.size); + ReadPSPFile(fileDataPath2, textureDataPNG, info2.size, NULL); unsigned char *textureData; int w,h; @@ -730,7 +736,7 @@ void SavedataParam::SetFileInfo(int idx, PSPFileInfo &info, std::string saveName if (info2.exists) { u8 *sfoParam = new u8[(size_t)info2.size]; - ReadPSPFile(fileDataPath2, sfoParam, info2.size); + ReadPSPFile(fileDataPath2, sfoParam, info2.size, NULL); ParamSFOData sfoFile; if (sfoFile.ReadSFO(sfoParam,(size_t)info2.size)) { From 3e51224d861bf50e3eab2f200e19429b607a7505 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 5 Jan 2013 11:50:12 +0100 Subject: [PATCH 89/89] Re-enable viewport code. Let me know what it breaks by posting an issue. --- GPU/GLES/StateMapping.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/GPU/GLES/StateMapping.cpp b/GPU/GLES/StateMapping.cpp index 1ea3b7cc26..95792d31e3 100644 --- a/GPU/GLES/StateMapping.cpp +++ b/GPU/GLES/StateMapping.cpp @@ -181,7 +181,6 @@ void UpdateViewportAndProjection() { if (throughmode) { // No viewport transform here. Let's experiment with using region. - return; glViewport((0 + regionX1) * renderWidthFactor, (0 - regionY1) * renderHeightFactor, (regionX2 - regionX1) * renderWidthFactor, (regionY2 - regionY1) * renderHeightFactor); } else { // These we can turn into a glViewport call, offset by offsetX and offsetY. Math after. @@ -203,8 +202,6 @@ void UpdateViewportAndProjection() { gstate_c.vpWidth = vpXa * 2; gstate_c.vpHeight = -vpYa * 2; - return; - float vpWidth = fabsf(gstate_c.vpWidth); float vpHeight = fabsf(gstate_c.vpHeight);