From d1851f0ded5e7d5555be3c839a47f057d6952131 Mon Sep 17 00:00:00 2001 From: Adam Sawicki Date: Thu, 11 Mar 2021 15:16:30 +0100 Subject: [PATCH] Rebuilt binaries, regenerated documentation --- bin/VmaReplay_Release_vs2019.exe | Bin 243200 -> 242688 bytes bin/VulkanSample_Release_vs2019.exe | Bin 327680 -> 375296 bytes docs/html/defragmentation.html | 18 +- docs/html/deprecated.html | 6 +- docs/html/globals.html | 3 - docs/html/globals_func.html | 3 - docs/html/search/all_11.js | 27 +- docs/html/search/classes_0.js | 42 +- docs/html/search/defines_0.js | 16 +- docs/html/search/enums_0.js | 12 +- docs/html/search/enumvalues_0.js | 84 +- docs/html/search/files_0.js | 2 +- docs/html/search/functions_0.js | 103 +- docs/html/search/pages_0.js | 2 +- docs/html/search/pages_1.js | 6 +- docs/html/search/pages_2.js | 6 +- docs/html/search/pages_3.js | 2 +- docs/html/search/pages_4.js | 2 +- docs/html/search/pages_5.js | 2 +- docs/html/search/pages_6.js | 2 +- docs/html/search/pages_7.js | 2 +- docs/html/search/pages_8.js | 6 +- docs/html/search/pages_9.js | 4 +- docs/html/search/pages_a.js | 6 +- docs/html/search/typedefs_0.js | 4 +- docs/html/search/typedefs_1.js | 56 +- docs/html/search/variables_0.js | 14 +- docs/html/search/variables_1.js | 12 +- docs/html/search/variables_2.js | 2 +- docs/html/search/variables_3.js | 6 +- docs/html/search/variables_4.js | 4 +- docs/html/search/variables_5.js | 2 +- docs/html/search/variables_6.js | 28 +- docs/html/search/variables_7.js | 2 +- docs/html/search/variables_8.js | 40 +- docs/html/search/variables_9.js | 2 +- docs/html/search/variables_a.js | 2 +- docs/html/search/variables_b.js | 2 +- docs/html/search/variables_c.js | 16 +- docs/html/search/variables_d.js | 36 +- .../html/struct_vma_defragmentation_info.html | 2 +- docs/html/vk__mem__alloc_8h.html | 44 +- docs/html/vk__mem__alloc_8h_source.html | 30497 ++++++++-------- 43 files changed, 15669 insertions(+), 15458 deletions(-) diff --git a/bin/VmaReplay_Release_vs2019.exe b/bin/VmaReplay_Release_vs2019.exe index f8712c83f76f030f3791f97b1bf203793adb22de..68c4280707b32489160b9e9e86102040e12d9f0f 100644 GIT binary patch delta 58458 zcmZ@>34Be*_kS}uN6;JKcqLq}U% zt6FU-8YHyU#IANl6-8TZUm9E05~|++d+rTM`2BtQa%avtGjrz5oHJ+6%)QOL;gjj~ zS=yd?EsN`9Jyq2sc=?pEDbIeZD;KA{k9@J`1j`cbInlC4dycX!)t+N4@8FqPeT?N@ zJl!J4SR|gyr;JGn#?#_CRHL(aE>BsZeXtPocauL z$578unfuf-?B)i;6CHXjPc&vD*e0=z`LSbS0~=fEk6l3f0=-)V@nD|?`AD7uXfK|7 zL}%WJWr_(r$mduv0QqhPLkOOW#k)X!DfZy+)|@|hRn|^%7{l|pp>W-LZa9X2$lEEu zv@~Bx`OMP18BG_atrzXwKjr<`iQn93dq<3SGbj#AXoxdubIy2=cJ6$|2ja7e@0i#J z+@PqI(CJF_G3WC4MRKK~eChi+Usn2=@og)G!+Qwtwle3AcN}A%h^9V!*amUa=WTv& zg&1x6m^WJ?Oum!&H_OFb-y>|juvE$9X(H!DmCcM7ECa5lSm~F<2QL#>{eEQYa&r9} zFt$eg9PpG6S)B88wP40pi6?>Q`ItrGZ1vYF?o_$K;usK`Do)8DVXm>-`$UkNVM@n; zOs}_k5+v@{h_Aem0C5D^B;tZ%D_bZZPx+z37Sw^&6nlf(u!rJt&|S7t+^pGz?^_^h z)|&0MegT&s2C-`5t6FBBut5A*>wP|YzId;81OJZmso5l^*xeNMM@2pCeDtn3Q+p(P zSF{UG=daBZTZ8L`G@S=3^-hsnQuG6hdQh=X@il|mKBKx>J>mRmg}58sn)}boXcVnD-SK5w>|*{}gyEIw-3(r?6U zZYZkm3YfYUb3{?kJAZYE!iK-{Ro?TO-+l4i34W!tXVzjT)jv%4U4LK zWhP42a|PU5T~hLma#WT@!Wt%cyL2dT%>*F+Qf@Dw+=O z@GfToB0qiu&%G>0CKPq~{t{Yr7{C6G8=PzYbh%VN#nIKYrXO!^t)FjC$|uVrJJyRgXL>&x!qYv7>7!ANIPq)Kv*Lzksb+wl1gt zv%2o~6BbLGs)fbn>-wypSYZj}wthKZTdr1S1H=dYMzH>ZzrGfKKYBfuy&Hr0QKf~X?;;!~Lc3@Ye=MU_~`iRQ||6qH?zClY_bJ1(? z7B)w?r=EpL|0(r6J14ddnZ^c+u%UC=Me)VZh5XY5(Pr3w)?_M3}%MLoH4#3G(LNP{MfoDb3?BfsTO2jnam^&aP6w-xorI(hT9 z!Z>b_>2!>4k>klC504RVkK4tMw-HOnx8pzW5|hT)=9Bf@++E@ra)DZoH4+Uc1oLlN zYlO%0#M}vo`Q28+GBJ+lv=ZvXU@lsTFD7>99b1Vf0J^mjv1!3xzqRBBSHS(=V%tPB zf2XC`lorQ(wiHEa!92R9s61&t|2$eOpEQ75qQ%`w>8zs|Ie9-M+GNUp$o}ss=}qgr z$_@#iu%2?=)4f=zwlAb#MF!i z>=m&pBgVf2H)Q8$_{07h%<6dsw&{;(;ml~__cCIHXf!qQf51D7k^d9kM|?U}VdKS} zsSW+&UTP*wgiou@;zXBeb@+n>F>0Ebe~}<^rZw)vX^Hj4{yZDj6Z&f78UsMw9a?}&f!7b2cjp7w&Kz-lZdEoyJe(6LLTy#qRMBQ` zq!^CW2r&(*kCEyua*?`@R73F)snD#dY@TRii}Y*$lJKUAX|_oJm*Edaiac8rzo?fA zR1*(T;AQw9=^`d8^nVnXEhc8|s1kFMVTC(HeomC4{@|Q0T4k@Udhr#~r$wRhuu`N_ zkAuba?4Ha=#LSDr-_i4G@&)U2=FMBj`N7X~!t8O3e-I=_E^Nlf1c{Xk8$+}9Ega3l zMWp&ZZ(BngQJZnE8sf3q7+r6$=v@{jzFE|bHOi^%Xvq1=01>^U0pA!P-dGaC>Wdjm zHt=iyqTbSGe2c&6xilQ3F>C2S{?!t3dFiW6il)m}vk-A?*+u?FRk87%W<0#A`01T+ zR!6uAvwvNZO?qv`5pZG>b>paWT3wMU8uPi1oJHa~LkA|U@DK1YK#8kDV3;0J)K9oD zZsPqFacqaUu;NcX%SRNv+l9CE5tU?j{+m(smz~1a7`b7o;z(KN9BwygsZ-92NF~6x zQ61|rLr7fJjpCqO$vgZkQdb5rPce1nLNvgfldq?# zN@8dT65V}GRWO$7w^3N@lx$aevc<6@rh>tc;%NDF#8Sm|GQ}~q*sKOC*_YD8NjmQ} zWrh?G`kB=()fI@Y5+;IKHMvd|RRrD@5EcO;WxF!=DGo=Br(rPKG($-(4Noy|bv=IAQ+&R< zE_D6a>egZHzy}!gQ%}JSI)FLj?6=6}Dx3uYx&n-i(3pC`72w@SoL*B?B(3ShwhH^2 zR(?Kfm_aRe1&nA|Lh)upP(-qW!nG!;=Cv>m+iVGqaRsD=(|Yk^gA%gyV({7)zBA4< z09QN%E*BrJoyI;EHP+SVzG0%nx?$EC%eetQ`a$$gar(UFa+&((|D%{1A1nd-Iv-8f zf#y=+9p`lb(T@fb(T@doO7~V2+pJVy#ncHYhcSXM6LgF(Fku?T7nrt$>7`@tSb_4= zPHia3mO2BVc#;`Dm|3QH(CR}`&}w$7uZ8MV3g#SV6#d{JNu2DmLQ9&Pgsi=wXB2qsX*LbyM(X;@Zl)j^{P zbe2H%)D_tA64_LO73gI7I><(#FU5BsM_4CQau%?*xZRJaf#IkvvrNe$ddUSkNG0-a zI%ug5T1TK*9kfyh{YP>S(?RP9lzm3)BNWr@?@`+iRA?s(711Evr`$&5Y;nIoBw4%x zpcgeL094c~7Dubs`*6buQ=KeWJ~BmF5qX#dDcSkr-%lzg7gGhph}O2xOPTZUVbDxI zZ;KOJZSd|+Iz2vdxiaG_7_f4fvIgrD=)(ah)`W^VjGHMPViVmyt>O7Cr42SQ;nScB z*C~BfEdI1bcp@b~o$GQXs*A2hdBG&BSy!9jsV=`7h6id%Ad)Om_-U}`o0LqQD||M# zXnYnsDQBZ+CBcGL5>F~gYZ+9ANZhg0-dMZl@07ka2UGZ9>@@eucCzLQY0Rc4;-iht z;N_p$D64;4k+j&onPTsR9#%`Cm9esOcV#i>vt(YkmN@=dbkLT25a+B4itSPS6cdFH z9LDBjPZZyaaiBCR{;nix2YoB*yXGHxk zIy0LX^F=a`2@*TMFteNQY)WRIi>{k2ymt-p-ljS*th+YVWTV8nO?4aW`n#m@$MI7F z6V-e)K5Qfz>+{b3vs^9<7OXHuOxztLT5aAM^gVR`IjiJsJB;6q01p#q3fJb=*0*0q zFDG=JnKVOsg@#~pi+6sQ%M3+zZE=<|)K&GS*MORuzBPj;!WJxThIBI(qS>D2Y%`ly z)5W@JAwZvxFgwE()kkq8Fr~J=f-Uah?Uz`z6A!RKUsmI9J`japhVqHO3)7a!I#V>- z5}9HXiOP-N3GJ-77T8S#2hG{4QM;!t?zbDIeC|NV1x*{lf^z{@ ztfG(0Qtm24`GHPp8wScj(}nL>5iCu#|Ehj?4~?j#D}}o1yf=hQ`MA(jMNJPKrP%hz z4=(&&EchynxA)8W>Z{jTmyiD{WukqGS^y?K(F&b&cAlz>wv^*(Wr#6P&w=tqQ}7i_LexC*T%Y;84_b6>)(RWy91wC+YR+T z<@|gKjbU#%JlZ%qzn5ffk~Su)CunsGOHubL4v(`{w7Cg8MZgf}y%R4ADCzf7X_|EH z*g^*8uQXDmk3+@6U5)q$MIvWc1Y($1cQp?A7Xbb)Pz85bx@2B zN+8f89TcyF`Viu>=|ckS%V#Fn$|jok+5;2Y@Dz50O)B`5}s4&3>Z3H;%Gi$nK`>@5m}@PjVp7Q2v~rua5k$ls};7QK#`P<#*_LTD>d1 zkp#d79YC&RJ(9=@Jx{J=JIZJ4`FP}CqkM**Ctr39<=-49D(-1wUE2@o7KC%u`c7ls zVf+Fxy$>~j(EE@}bd|I$_2Cp{{~i0h4^GM#>3QlyG377mdFq1~_2H z4kQHXLkt1F&FB-jKBl&2P&%9w@!z!wio04y zTk<@$`8Tf@=zkH5zFSD9BEJ)RU-ZxK%zJu>_4x{~=pk z<3x?=#%VBGq=m6m-?#o)s_!sPXCdpkuR?achmmpGE`kq*@d{Uja;OF8$HmM;ErOU< zqQrpT)mO)43yN$IhYyWmyG8WjmhAVOQHK$_-Y#|>3F~pU1}h8<$E=5p<+kU$V`#Vz1OnJ@*T!({6fnrbHhA#Er# zm`lBYROb>g;rr;|`cD|0U7Vv$jO!w#hLFux(sTG^OD>AEM)bMIkm}qkVvjwoJ@s_y_`n`xqiZZi z$dSCE>H|fe;{yi1|04>{+3!T35(W(}=S=*1s+}{_bBM5E##@D?3$YPq%0_1$J_1@=T4`zsd|nZp0C;0oFBYVMvA?!IlrDw zU0gz2#{}ASK*Z!A-V?8%>HpfOUPPR-E>S(K*exXsy76MME+jxgNHCLkyr?t#j+TnG zWI<2rj2@5bD=PdD$!nYut$t|hJ>i#Ul5#H)Z~xFL$e z`$_npO@Qg?b2gE`@wZrYHi`TFEq*(jgoEGkbDdeXNITb=ceo?+&L!a-@+m+YMbh~< zdB@vg)A{CnqFG!$-+|p0!9QBs966~w1diSqa0(y1+MBckQ(yBYdgELQ!4d+HXtdyF z?~Tq);=><@F-3S>sLKqZ(S@X{Tf5OH{9{pXSt5$SZ~Q-E_Jw%g#amo1gvh)U+ieEu zZE@m4_jXH;VZyg_1+2XZwXl$HX;!^M$+I=v-9v40lMlQkwkFj5z*j}zpIX(9p<;CK ziEx`gs!~)(j}krIa8!KuQ!qTd!#}lXuwy?}QzFJnx}H95OD;-!Xgs{xkimuBdx$z0 z8?jGvx?HTmf@_T>l{IC3hT+%u6Ysx5H_00o|lYKC>10uqFbCz4+ii za+X|ez^u;E%#ekFa*&>?U41QB(4uye*1AMILeWLj%J%m7x23%ugjOE6gD;y>mg0*t z6zz3ic5_SJcBYtLRO;E^RxhoOI#z`G$jsI^i>|-CTHjBrtbE4?v?$ZDEs9usC63?u zje5qH|0dd9?a5#HP4C)atk?fv*OZsKwt06cE7Y|&VqWZ;T85&eYmVkRzmc6^?AoB+ zFLbRZ>Z7i?brxf(H#+%v+KqCSDH9@%+6GJEo zwMJf*-6y= z^Oexv8os0-S9J|q(?st_8YW_5YJ=PNlI|8!?8N^EupS)Dsdd6|l8H(-vG zs7*;JTS9s6ca|wp!hN3Bj;3oRg}S{^Xik|z#Qi+I87FU;Ae6#}+~*6CRu~ynRU<3u z1pFORp#F_vCU=V5!YJ->Ij69&wl)Y}MYZ|hpG2dg&Q=r76EfrSzXrJ}YYGN|JR(}^ zqMV5d<=mnu=dd?1KVB>AX}RZ=3ZShXX=+*rEq>O4W>Q(oi(i#emc*p|p#$7$6}O54 zd6!+n^F|m?*(jRdh^o^~BQEJlN$f%5q`-MM4z9)pk$EH9zbzP7)H|AYN+-QxrtH_n zp&QZGyBC1a0YNm9*$+%vZ7H!UhYSLK@ur>UmAnS^>t$VEb@!+eeaf^mF|@8?+H$%i zU9U{KewlP=nRJ6P>4s&}evL{p+CyDJ4T>H=*R~>-Tv3Tl^G!D?u?6WJ6gA$9vKfEV z@l7)&c5iy)%(yq9P=@rWiWW(rLAcogy(x9>qMY7vuZwV)jfsE=6$O4aZ!HxqG@2Z} zE!wflIcN9w&o#Pk33X-}>XM+#V`!|iL3`2fR<`BjNSi<9X}z;_&U3JT*!@y`9NtpA(sPqS^6wK*A-0k|EfrYtR-Oj`%XCei#+>*nK+YgHX}S~ihptO{L9lYY*AI%Q56oG>V1 zV8VdGg9h$%wvVDim)22Y<)daH#UGa$S_~-}jf5bWG28wythw)sKOcp$n>oIZ0~x>n zwg~^XfS>tH-1s-N`<9PNr`>6?dJbbDj(wcHnqto7mz|*5Whl4lln+5k-N4zI)=r(K zV(^p3+-;>$pVZ?1ABoSN)T;LQ!!o=b(Ru3>C@wu|#2)9k{TI)8+YpiTbO?_5KYglH zjXXsCF4jWgFsFx|X2D!>)^`Dhh>trnK7p6{T3NDn~q5n-Z;Q zUxuUdTY~u3)x7f4?O;vY`z#laT#efl zVsap^Nppk@SSr$cO46f{{=6iOV^@#!S~@8c$$cx{U_&Y`({%f!Gjscj1MD{Mv0v_F ztX1_I`_Tl<9%7e!a2{Ror*GwAdt93h(v7pwnk!eKrx}5oON3s|YY5&G!Vt5Gdnh|{ z*2o&T9>wiRTNQ`muGmxZqtDoV@yt^Y!&Q54RU-B(1;t#k6|H{g?mtZF!im}*$6-JbXX7!Lt~mbIGLiG8uN#ZBR=~7PkHp=A z%pg)sM?6v5!_kKlki)SRM=Z`yQYb=@Jql>F=nL&j)!EqU?26z)Qnm}?qO%x85mFP| z#x?$c8)nxsJNhtl?0*ncQ>a9SClbBM+#PNR<^tvxFi#Y~q4gZO&y6(<93i8n|ucQ(yRI-taQ%)=wS3xO@MUXv?WVihmQ)0XcG+!)|8oJHZd zceK>3o_^M4zX`BvuKgCwvVN#L9aI+8gX&9(eQ3(s2FY6-adDyCK-E4!EyH|apixxg zU8s?K>dxw=u6>VYL5SiA7>W=>e3r{>O8U{Fp0KF6d|_HM4{H6Opl0tm^N;f*nE?%-BXt< zS*^8CiT%ekHxe0J+})Mjz-DT}3C)UsN*uf&ic`gHOlROYAkP>WLJXA5gB>f%5M3xk z)ZU6Q0xywh-R#P@*gfhKn zBFaJTq@(vzXQ&@FXdF#k9j;I5-b=B1Y}AhJF(r-t3G<~qS%Jm$J&wAMIk(`}LJ^O? zWQ*Gvd#K^Hs~N_AqDS9IIx)3o(`A{1*-P=4*=MG4jU;)c(G2cBeY75s5C)6R1|~``~<(Qh%{jcvL!j8$@75DVn#-^!sCS##^7g^(wm>n9Z}j@l6`xWN`z9e)k8 z>) zYoN~PGf9rl9AgT&FW`zANXc$m@&dwb(PwnzJsDn!b>smb$nlj}ZT{eWxu_BgdS&TG z*l_!-!xq$lDX1Gv^`tAH_csiDKgPXjo`DsBoQ}ODi4ApVOs|;L2T-+Z^7l%tG20=1 zE3?*>{|MJ6(go)%ANgu!=I4`&(kPce<-F_2$(30fuZXW{_>Aw%ZIxMcp9}91%fxXX zz>C_t0Fx?2ISQymdWd> zR0VdJHrDajK@!dqn(7RA@~(-sk@-gE!5>Ol;KKst6(jSk{O|$UVk+m5cZ|%Rul$!N zJ+IO1dt0ZZ<8x}``&!T1@b!J(2I7GwZPe6CRv1Pl|C7zDusR_Jp4To+&r4v{D=D!? zx_nq1%Ov9JjcV$xtbF{8qiUsP5c4l7Qm-7Y zA88%C0XNGzZ-p*`?!L^k?gMh8G!fJ)Em!e*gN^iZ6RBK9yLr9~<~FA`ZSCskoF+)pD9Y=l)4l?5Dy%IGY9=KZ`O z+!ZNlXuB+|!rEE4!FxI86hfC@sxurD$yUrwSwULRHm>cjPhHrcJZ=&>~`Kh7IAU~?g zTGWif?v4DL5L5OX;B3WiCL3KLw|ktCx2v*NUKhRsf!*Uh*~E`Uvu|apAB*=M4xrs* zG4!r*nPmQ~u{`g`e5;*@Nh<6IzS_fG!j%(4i~I#11@eg>EW+ChWxPMD#)mGH{rp)% zoti`o&rYKyd(a}^v@_rC;YM%=lbiimcoQq&38tNf_RTYlTiF7Sp6>veQc?)V3t9sm z2pGfU(g4;148{kry5V9OMj$p|IUeZ&CSR;arYdl=Jl+Ptw{Sm(LW^ZNgP_-se(30dlmJf(sYhi7g^_kN?2qPWSSp~vYyyNlJTa3 zB-IRfV>Fvh_w}*OzWFbVj4f{V0!SyL8fxfW2{rioyIfzx{J07Sqf=;k8kP-%OHSyHVx9r}V<8wO5uSPv%UgBEvBW8LMH>a49b>`R*V zl|TpgNKNr2Te@lyx%jI>L(qG8`FP!C3f{Gu5du$t;676wL!)43n1VW#Di6R$*sLf?h0Z<_(u!1Jo`|#tjUsiCq2tMej%4r z{x`e4R1=Hde!F~JlTGA3?Q(1_7|fRPvs!3t-vaq>EucSMAcJZH9lbzD`^zJ>fnGmf z)(i$ZYrbq3%o2Hr`Fi7UdEN`g>SvexgIO!yznc6vm^H7r)tejc(ydv%=>;vvhEE}H z^R25G8l(%OD$8zlSRZ~lTYgf9)vKMC4TO3@bB5Gv7)6WP*~=2K*EwMYjux6Xh>|Bm zu-bf-Eo+6aCSHrMt2^eL{k!ZD!n*S9%jN12)`mN?&Cb-Q*LVjK%`YJYsfO# zdFk1RMf16{^=jtGUX55>hugD=^TQO+sREzAkz%`cO|dJ*w8!1&3J6^bPU$9YMFJES zfI2!~!#UZNr!Lt&i3iBbjacoZLegrSs%ihA7Pyh3#GW$E$BQSJqAkzift~$RdYNx> zxZ>#6NQpgRns*UUXCm=HXBKPZoz5(Xhs=_1gt6AvZf0zV>k!i6-ob3gf1SPX!@i?9 zJ#fT`(rtsij$%6mJu1$)N8x|C#{+P~7?*zHX^%wv^^k-?=uOdT^d=gv&tWCvuwpCl zR0;~+%(3~3smn>~B=oOXQTP3$d{Oj`bEoHJ_#XHteZpD&%KK)KdOwD~7s&SEtbdE% ztH78&>6FrTAPh2Y&yW%50V~d#CxdH}$AeS{}^_sQSt2#_oW%S1#^T~ZsSF~PN%V%}v>vh$fDSvIuQu&yl zWMTxX%l?!jBG?n2{FWTvgsoy0$s$=~K$Qh_ScV&Yjufwy2%PetcRrm@Gr5Ildm6YF z)8))a7USg$_wbmLKat-=GH2bq|LBtQ+wTHqu@A?Y<0063nj5?5>bP_BRC%B&`-Wfj zkZW78p1J3nu^X(;`*4F?0Rym@>xGh{Z(8i*Lc_M+v9fW zU!6u?Y|9?;)njtcwPPu~@@}|W7WJ;8w#t){aV(s@EBnT=VSMLE`Arb34Q2E*vDCoiU^%21)NOEZFPJU>Z{6 zKG~uROY+Lrb5o_Y3v1xhgK{OK)@!ir(t$PU_Qz~$`0zk5=AbvSRAEab$QZ)Ii9S=QhWSz4i(thJ~^W= z3-$~lHTFr#UDpq;E6dN_@j4sN`5Q4ZbO0OI(Az|frFc=K#O);Fs!rLDATw#|(hEoM zS5_)==KxH}_vLQ`*sO-_eO@ebsBf7fF;wJm7ddYr%i`}CrS~A#fR8oG=s~P5SB$dH zAePYD!^jM~2294G>IizzMLnvhGkg_CU+ygOCd>$6EH7YAd&}d4SoK=D8bvxN;5C&i zyV_f_!E7-%ddp>lSroriS?(LmI`9uFOSe?k#5f)oGI6r&Wy*ZH4jLZf!9q+jw#zB(v z=hx(*q0GU4kvE32`aZ4TwLiPAQ+KGWJ&eWBOHDX{aI;TLqt|=%*LRBKm|-jye%U9( zSeWsICpFjwhCHCrdUX9nxc6nn;Vhhw@surxL#bMM%F)AF1EWuAss2ah z2g4!lYZc_4;jBw7S>btw-Ulgp^q_l%dIvj&G3QKKWhAR9+rP=ecuWO3;!W1k`<{nR zju6Rdx&2MnCHzA`aHa>2=(@BU6#JmFad)DEO~kC3hOz6zoNs%`&=IVGch8av(1DGz z_Xt+6T7zeh=S>^bS&DRwU=59h?$5dFb42Ek0OMb~%imB@Ba0z@47hbRDW+gWxwhUa zE%jJ78_DWLb$tdY+lIw?_92z6jF;2jzeg#Y&d>}!9w+CFWUun?-Q?MkmSW^NuLRUz4*&qxgSJemI)7_x_GOFPS9^3A0SY_{+LuFbS1XbnSz3$QV={ z#3Zg@G+_V8tK&fK>q#AG<1G!(E5hK81!lB?n(&wAvEVSG6zzXN&K}F^y8Y+E_INCd z_5RL99*x%RO|lS0-If96Gmgatz4{#0&Fi4M=PX6-Q(bX=?|jQczB!JC8vUN*1HAUj zcgLaH-=7-fZs6SZAo0sM7Q!#NOSkbX#yI5Z^L9G#lgfAyM}ubEc<^xlzvs9sGG{#4 zKlGpcaXchsFU3ribtVAQ|3BGj0_zY|^EswGbDiAe2NPIL{>KxUH-R;C*%O(cu`)h-QPO$e0=Z@)>c9N2+&huQ8CPpBtZQ-^nlHW6fST~H zj7no|y`xJ}hh;_@tIys4mG1*%Jfgi@t`(Z_oxDbc-hV9JC!vo6OHq?$*GVYU^s!8v z#2WGnkLAiq;H-{8em9A|#fLwV?IyGOZdQy#>SWg1SV4QsT&p!=k6b?)wfztT1GzOFCTG_J`FlER=)LU0^9rxXzzkG4^nq-j!D4xX2lA~9 zNW9e(`B?^w3HtiJPD!7N!1NhtE}1^R{VV^?zzEH|FRM>w5h3qEoV2QG|4R3oj3o;t-A<<;-{|5 z4vWEYr|a_QV(bNa=H6V)LYPmB21Jb4bU^&iud?P+)`$;XB@^*v+vK>VtZ}7ztu(QD zG+Zs$Erqm-{d0FNWf#1yiuy=3rzY&`0aqdWhy|gcs06jZj_Y~=B&s8a?~X#kl(;v+ zlz2M&f#QbGgY*i;+f|BvduX0UbH$>zkHIxPwXvg*VzJK*jY)KL3rny)VW#Z25Mj$c zLh+sMqfkSEQt*q1qPoXeRDY(PNXd3TW6J6-tE^%E)l*b=oS}l^nupoZ!&h;`ZmxwX z`*#_)h6RGpzN0LTX*ePShbbytM4S*JmYk5MfC)u?ni6|)O24+-HNI2S!+Erkv6vDM zTih0fu0z@!`{R^|6qPApMr%Sr6NgQ85>dKsb5r&W#Hr|9%2p5p(#b`ZSe%7UaZ_CT z&{~3@?FqN2!$YGohL{~Gu9VozQ~Jrj*RbGvxLfQ>Z=Ry!wcHZkUnSm4Dnr8bc{6&g4E0-KepD(h`xSi4(^=PTNVG-B^c1d>;Xcx4yJaCG4V} z;!aFbc0Ptk`ds2}P@JCVqRSN#} zP}~p*^)$!cnc{DusKQw&7R`nIr=C|w;(N1PO%ShXuArJOKdY(B|6kSH<*TasysD#M zN~`JwRppB_t7FGrD?M;ynbv6#V+(w--Nx*-&^ro&?&R$!i-C3E3)-f5!Up8+o~nK8G{O-4*%vCYFF@;+st@bKr^` zW_Sg^Nc`I1w-i5ut=!HGGw>UU-(>vW!H;0pTts?zFvFMleU0B#3-&f1m&RxEZRbss99=Yx-M67RoOV5DZhhMP^ z%=^Eu>5x-Vk30YQT3*`DHgfaVGJ6Lb#0z)J-*>RC#yXlmcb-U=?Ur#n*&%*-m#mP> z;<$a6Ov+{Numkc!E=#UciME3dk1sOtu)D=SILOkCyTizyz;T~-Q{v+LIbOk-TYVSH zI?K%5EzO$EwvZ=Ybdzp!Tl+@g^f~Vu zsXxAgTGl^+GptKD<-h~1P2>X29oA`Ef|jTd_P2NSis=@DM|Fi3EISSx93J;% z!2yV-u6i>WxHoQ|Mt0{&8qNo^&OQ7W}fYUYO!U3jS%~Lkn%? zPdImi2Djy~(S?mZq}UF4nPXvmvO=xoQk1kic|TRR4uEIPmv*xc{M@AM2kAZ4Zm?Dr z=qnkm)lG+E=&;ar(yaPFQPelQsHr9uiLDCC!%KG*Q^6`{o+kdx7@R=T7cowEbGSq5 zG~dnYF=x$D+rd2W+{!fT2pvx`k`6D(9zuuxD zz{wwR;c+6j?TDR8(gvBJzf;@e|v}*2$lLVu8BaK{)csPizmHEWf_U zy0Qn-^Ah$*et*e`OY9ZDyG|19>`^%Hz=fK=%z0YKS(n%)_OX2ZGIll#&&$P^VNt%8 zRexrmdD6i|{jR=p@6W7bFj%yxx6Nv=dtQoLPv5SpmY$?{d^{usxa5@f*tv4!lOw6W2(uyiGK1Eb3HW zy2M7sBIe6q{$c@g`gP{Z6CLvJKUf|4*>x6~*ym;9_4BB?&Rz*xl&MP?-q8s-)D^ZB zb zdx0G00r4#GnvAOH{S}kb7q6WYB<7{Ynme;!C{DdCNY;Bh`sLR8$OI?z8&I99`&sLj z*22(|7QTPEr-A>Yfng;L{Hql!H&i&a)WkXE<(l%dXcYZT%&cZ;5j)c8pBK_-HcqVa zGX0>emj&6*taq*B%Plv{l7s(bfi-t(z1F%Fn*noSvxd2*OrQ?0lFR;NepcJd)gD*$ zYLBD93zJ~?3*?yA)555>gwl2nrt1UL^ksq1c%e8`td4*mN}3z|a&wj!=&89;)Z7nR zkF{>~Lvvq2F-|(Wy)3oLWh%gnroDX;CnG^e+p+T4tT6`b)bUg_>tzX^p8K+7B1>4^ zp>?s`P=E9SInCS{syZB1>ofN@Zg->6c)Xa=o17pZy=C1(48jX#Y1$s>q7Opc%S|KctT)={<%&DKK#pM^I8D>a@3r1* zl0G`MV&#VF9PW{kkxPBKrp=k8m38^|^GFfv$%aMDC!qLc zj*~K_xrhY^tVnxFN>wxE%p%sp>hrQ#j#^6vSavr41FND>;h!{?UU?S9r~baH73zXe zU4^n`zC)QZu4pPeMmpJtc8sGd%jq)m27J(J8)d&6Yz@C|l*KpLC@f4vZo)D0kuz^1 z+D{98uh5q2f%)@6u;nHj!fwbaw-Ao%eqJ`Z#XiJReB>5lc=dP6nzyls3p^(W-)7@b z{@88Si4Qz0tK30kG4f-XaEEnc$8(q7!5Oj7S*&+B$Our6+Eb-!O&)dD|4hz!f@%)PjZfI;{PT?5UjMNwjQ^P?M?Pf{^>(KbYn^&% zu6S3);&4BJl6d{r-wXGu+?>gCbGJWbmE8D=ESb;vQ0!3ZbN(-%V3Q$kJdKYVllzVv zugkf4l-%LL+henJ*Mpzs2d(mO1wNJ^86jJF@qO!;ahf{&8BEAf`x z=dIj3m3VW;W1X_TH*dx_)sVfs`TN{wm%QW619@CMS<%RCEKNF$+!_#6of`u2`!^8x z)bOl|Uy!Wp!|$>}>2Km&c*TM8fQg>z45YAH>)aIiU*bU9?`Vt->4gPTS?tDtuMY z@vlmK)m=#AShY(Uz7dr^Sk9@+gIoHk2{;V$#|JllbvL`6#tpH_oEq`+r1ZRllQ9fQ1>X@R*|**_)PQ10^^#ETP{h55zY)V z`LYC4l?oZwb6l?@;NTZ#$#bqL53)qReh#m@M5wJDVwgBzgFzJ&$H&J|Dx8#2Xq z&`Yruv5cE|ODqQaC+D_A+~BuwIc%g>x17QQUmo;Q?DH=m3B)x#v@3k}wb!jkqnr~D zY=*XICGH@Dg7jfDJPc5J6!OBuzBV6!=UCkhzVU|16-FHD;su8K=11eIOP79%y~`+i z%_GK5tFjpUJDabey<0+_7uR6)%|vHyz=+ifgt8{&VH1!0uO)=&5Fvfhj`RL%jdOgv zFrU75fUlCF1#|`e1A5cFpPp1GoodFnT}h?!Y7ELtYFts5P={TTDg#XWVB<4bb-?I* zj8%4l(zj$h75kD?Mwt=7o6~*)u1}01JtaXsm)LeoOAmu#Y69-}sc;9n$b$hqrt#hc z^*&HkuW6nKdO_E3rsIhVf?IH5&oE+XqWVWiHS15=s2ZXg&TYF&@ zk5cTh%Arm~YQVR@75mug(KqoIH-S3gdcO(t_oG3k4QOCvTxgs4Guje-FIeJGLwdCr#9(wMP zRnPX*v;Fm4s-C;A=SJzdwR$d1&yCg_oUZ3$bzG*N`&rK|&~qg%EJbc|XE3lt$F3~F zR@AfW^lS+O8};0|FSR~y)pHN^Tps1JaomDyxad$NvzqCvfsViy6`1XMPEGa#qIx-m zmQ#~)S2Z)_8N#X+(XwhX?qXzyJ;P`SEvF`j01;IVq2<)%Fd$;eA+(&Dj5vN~d^v=c zQyM89$fEvF`9%4VjPLuffQ88#tvR5^r}Q^VdW@VY7~Pu z8LZR{;Xo2qj-;MO(q6BGP@sq@N8zhc1nCrn0!4f|il+h8nc^>ivfBs+3Z)!{^@&Du zUMC?ONP3hbd8|=v*C_}EihkuN?r0S6=oEwkMQS;UKQxLooq|xH7)2CTO{^re>l#Tn zorG{8Nh?>$uNp-Yoq|xHm|l+JltxiWryvw4GRsly(I}js17)`X1^L^)UQmu?lSXn- zCm|FlmX@P6 zBpb_BGEJjsu2T>S6kE$tjMpekIt8IXk@uW}X6`VJVzo{|sLUBwFGG4F2+MP<6CU^s zb=Yk$aI7;tTB~ZkPC*Q3&Zwx@RGw{}ZiY_xKiF>T2pFtY^}0?%d}q$UN9J+9`~vsg zHM(DPI;ijEV1Ai@%jE7l{9R)c_z#5?^H#+*qZ}B*+x0&184eq9p&MSL;Q_wWh4aUw z8UcBDsx1-Afx|n#ppeI&Hq9rZM1*tGl4ym_3cZ7Tf_nNNlW$fi8J7h0h=PFsDEVUu z?-Eq#gx9{*LNVbqc&;?bSX*=BzZtSaI1yd%qpm5-jS5JhZ5&t2L{p?jW;eQ8!}+#c=dq zkciJD^+?1WfL?U^kec2NhvIla=o&oAgk9uDnXFZkuHp2&fTHN8DoJ;o!)uU*J!Cd* zIiR>D-BDtbil-LrF_(>|Pa%`d5NzV@wyXjEW^bu5~h;&r9jm75l)A^r7uE5Uj*^9G8-( zo>m0E@j-e8#h$UQ=oby0Y4t{RTT{1xK-J}?H>c8m_;5Lzp<4z<)9zoYO!h3Qfr1(S zs4NeaZPh9}l$4KgG-Sdd$J^A~#;&0ntf$h0Fml=2LP59V9Z82Z>VJT|5d8q}1@uc) zA5e@RS1~W+XktSqDxueaaY`{A4l!L=h^Gr5Sbl#@T!8xz3vfl8TuJzMiJ>7*yx(g; zq8}ZT%tl#Fgk~3R()M1USn)!QCd!o9`;)(<>l3NCt&pVt9aBef%%|;0vcnxGH%S*t z1N+_|Vu&2wQgBJv48}}Z3o!tY&Pli*{`as1nz9kj#RTv_iGxri4gp1p!XEewzu1%o z{Qw{1LVH-Xo|Jt3mn58OcAda0#CJ?PyN1{bS-P+75li>5s85T0Eb5G~B24E_VHR~d z;`)74E$T3@6nqL9>s^;oxCepj;#!~K(L*u`t~2p5(?To`+D~)`b3Y>PbX?}Q_PH#RwL>nvZT#)+G)$197^6)1*xLR~bKi!#6r#o_Q1aE5{_aRaKK>tS` z#nC;@x#}i9dxg$ryTN;YrUZ2Cf+Mb*=sosA&W?+5FBTUi6Hj7K(=nzb(IZ}QK}4De z6%35M*GU}6;fQ_)j*v>_-hVBO0R|FZ-ou;^q1IEhlO?}Qr047>8N*H2z5&sH;68b^ z0Z*v4sg8C)wqQ7rq=YevF&}GY!j!dGwr|KAR)jR@DDbVJa%@B1p1cg@;m;k_MgM3g zTj=|yqq=NV%^Dpn+-E?E9NJ?lju}vxnV5e#0IUX)h#VK@%8|HgyQjg_^+`8GCDo(M<$WOFzURNmeC?HW@Joy6V*O+Sa`~&Z~jQxLr62nCG-W zSJu$!?y&_K_f0#y)8sd0(OLloz{}p9kRny@p*ZG|T9S!}FMK&B*a90ditJrfqH3)L zbuBKhuF3C_eEY_9b+}uh2N34k{GMcz*Kt7mR)hrzL6%eu{h)b+D$Uq;>tErhQTsb>cHM?Tp)DxHPn{L{0H} z-wCK`V$2ArX=fCm_@TA z9z`KA1*iuxgX|+2mDMh_FtrZS?v^exwB3lnJAwLoDGx6a0(Dcp%TMStX&$NfgD&-1 zdK=;i=WwX2i?7+sl!({5^3&_dgb6&j&f6qXN4GQx2mJo%{QP&)c(R?g{V{_F$z?;C zUqtoZB`azltf_NuXck`ecxPnEa+(#I358H-IsH4gR}=nAC2K9ng+6hoGwh7ZgCW@$ zyN34UldogkouqQ=&+#!$wGq~Cs$n#6tqteg-4~Ivsb5lThfXeQ;BpmJcHDVCmv-}; zwIw?HCN5V!AHi6Z!OKC3ZNH>8tfqNn$q^!Z7J}-iZn{MxDw%VbTh8c9F~Q~M*N>{U zNQ_5s3}!dH!UFa&Pg1gvn6hf2K8r)rr+F=owNZE^JN!56l;c(o1-n?mVS`qP8LGx!1m zx(oPp*L?ckuxq~djbXOL7a3X>dzfP@nN6K=E6-rYYqWr*n%h3EZbZ z3HQ(x{Es$BI@$O(L>cqG&AJfw+jSr@RvQh|+&QrRs>VHLUX4UGAIIIN3l(*~))Th^ zT$y-y2k-Yl3iIhh$Lf49{C$B|`%rRuTKcweQuLX`w(ruYPwi`QboWhA6Yg12)I@DK z&29|$j~@O_m7DDe)qyPrvf48q%oJ}eQz>Yo%&xs=1cTIhRH-HQ)a1>0nK!ZRVlA%L zUzu~r7gmeHYhCU=Z|DEo`_{0is`l?SYY#A-WDrnL&_Pi#4-uk~nhgp#803hkcpeqZ z10o_AmO7}I;z&~YxU9#XKb1XMnPFLKSz($|S&^O0vZ%C%v?8-Yvv_~^+Ixl#J|Euy z^?rE2Jab+5{@v?d_d4u#-fP`^k4^FOremv&9UJKy+b$jSy>{t{Bg1*bz~}U~NH;D* ztzw_5ky;2oY6Z}5Rf(Vx{N~Q+)azS%gsj_0N*L7_n#H6Myk9V;{ESL#v&~iU{=q;| zIf75@0#(s5$;V*N{qvFhX4Bi7kidPIn!4S}Gx&q0BL7yt%kZHH7{&MS-v^0< zqxc9zl(;;K|ALP$e0LjPWq4W4vm&~o;(jY1O0!zMl|MpwX9|DHX`Lk3?UG@@b;Qi0u7D9+sYXNAmtewkZLGukAms7-koEa++A4QCTpQJG(_Czue%qK?<%}ou zrk>b@m0PEu+38ax$a+u-eW>arF_&&~AuK1=z%j+bI4 z+DMzU`0g6sSZyE^n0Tz8Faf@WC3k9EDk}N2%Jk%rf8bv%Leo=I);9*(Do0^px20C5 zTWysqOsSPC%(lu|k(rf+7F%UuysdI_!lv|*tr2zQSkHZaJl*bO$+InZV1bsybph7} zC{;{v>DXnRRa7~vtnyz_MFIVb$_F6lfy#f;Xq-`*6lc3-mSx2t`B@+DuuE@m;4>y< z*%7*({*{6(wPuku>xe>2@z-dbRU748fMvO}Z8RT+gj`!qs35GvqGL9By{i%a|UO{VF{XZI^7BHQt|2%|6+oH9U z{ph$9Ct2vKm2Lydo7A?AX@0g#OD?r3p*rZq!B(kmi+Nnta$>?@joct_QpGz%%|rdd zm}=+278)ztnx*y*0<6NWehbrcnqt>qgwc76jb1gqVyjw9D+HPb>}um_P7OI?a*d9} zUwp`iO+4bb);8n5Q_-52PoxJ^r4Dn~5o)1#xGH|3g@(!JdBs8j#VLGI(vJ}Q=`;{~Qp!Z4O+27kZ0ZOQ(j zm^PO8GSrLJV|hQyncDaQvs?q?PNWr4YiVn6YsIm#{5eEZV&m4}@>Olo6o?}>-p`Ei zx&!GuR*4oHp9=l#4BjvCm3!Lsp9Ei>MQ^&M;}-GoHXa3Ir-Er|OYULuOa`B?1t0R~ z-EG0Y2Y+4g+z!Fd+%5KG@VEmBnS8dvU=!6@JgNJ9dMv}L!BT(czeeB`3pZ%1!Z_jn zY`*v^i$~l-2TW84@`>7FtE`B_K{Jk=Xio|UF;yF_G-I6YIAb*3B?jHW)8pZpSrv}T zPCc2BQMs<3+^(JPQ(a}ao|n$boit5L8vVAt(MW6z<+Hs3 z+J^Ha!@v22T&I31TH0nfSL4G$9b$Srx-F)A=o@uN8A&%FDj189aa`4SllxpRXjKKR zKzG6#EqoKEytH~udEAxOP&wK}$;MtEccCusUdPAA4UdgX`yBWE4>>-q=D1Pj7=@1YCDq?^2v7ebfSa&) zNY07*8O~ zDfIH8Er|+$CL+&rIkDiyXZUh4E@rw`TUE=J#Ovevxtq8nn|F0~K`3k*$mZHM0Mz2+ zwJEK~Qd}FU^`?$!3|SY0HxJP0N=B+tz9);Ir_DusGGrV1j@#9ZN??pMmZ9cgbK&J5 zyc+p}1(B&Sr6v9db8ITjw@@7z=$$$X>hV=^e`H{0Q=cJyLtcWVLAq_o=M{7)CwIj# zV&VDgaxtZ|Vu5t{A*UCN(n;H0{Sj?i#g8EyYEfG$FUp>=4Tr2YSG%l!jlEBqRVUv6 zP2IEzK9(8(Kcx=2>yY2c|x3sC8`~>>iJg;-xrSkEeOgqMevbQFbLm)f#TT{sy0Ii*B{PhCl8>qnTVO4f#AJSzXgt z&cyo9Gn|cChT$wjTN#B^;L%(b;vdYT(W-2DhMTApeZn08X>Z$@L`d8*locnLIYWCx<4VFK0I`Xs%v=&e_4QrjQ+0lI*#1|YL-L4 zgiLDP$8cMy@Xh5Ge%vI*;+|Y?j;0VVp7n(I)mIzpDUrzn|1}fNKL{7k z&E^q&ni>pW*xQ}U*4j?+Z^{53AYQ5T<6UlXjC+#pS8UR*{IA#)t8T)C4W(I$s~vj?X<& z9XG1k+9!5S z*UmDpcsoFr=!H-*Z#wU5P{d|}ky6@oW9ao+op{ER-a@f&IuAGGh%3{1pQ!hY)U>q% zoWMN=ctB0BC;tyoefgOus&gV1QStZ9!a0M-MA`LmeQ5B+b&Hnw3bWWdi$}xWpF$ZX zh-))=kH}Nl_xEOCk~h#RGM5%#^Yyp#wzo034YHW|hauvgnLMU@jy|qWnVflL8NZ`t z;ocAto5v#!d&Ji>xy5in=EO1#J3AfQelKq#k!m8*N(U_j!Izz>-8BV>{8>EFFiA!y zF3#fS80rntpLz;v9r7Xvc2Yn8x0o=GhjB+IwcRzT3E&%JQL|BrS;9IS|Aw?tm0C{G zO1eYGT=R)1;{B~MF2nzby|Z~2v|6clwpZzbnx!{ zmsS}Gnx)jUdi8p!dOiHHET<9PlLz+uQB%omH3wB{;GU=D17({I73{^2Jo$WCIOg#1 z9#3>oLPTayME$jhN;>FJL_53@O_mWEQbf>P_gnG#O6_+47WR2O+>#+R+7H7|c;gvxO>H?{ z0>mTJU^qHRt^Mw9e~MRz>M+c763%%XpQck||7V+?x6U`7^5k;$pECCN1s${ywbsz@ zzyOO0O*Z;swG|r%2}>T2GE5Z1^Dr~?(b{&SN$qI9Vq+e54Bz{qE#Mn6FMPG8@woUQ z4>qd@=ZY@*Jee2H750405fu}}o%wuV=q+<;I&@W8XduGV*;KJBpWDXuzP}Dnl3A`_ zQegg=>G~|iRc3NE_r8?s`jp-ww;DrIFQvHbL1{x;U1wVB(_BBNRgE{SZ}GWnY-W|u zrLBLp+VHO0mhysSV&r_D=l?3^>x{KWlZ;~TeBR`YDdH>vGz>Hnlm;3H^6sC2ktSzu zS|Q*h$*g{v5N8Vs*hHaSCVa5ibu}5A5x;mAyg0YRf;Vdx)zwzHpXJ)PgTmv}N&c|h zBOV)jmG?GF<5SmG>FL@iRW%*rrHXmQ~Y&!+bYwV$}Q0M$Kj zkm$ZpZZ51_$Zy6T13p`p4G3PuXYdzZ6N?w|9^nr*(q>#E&Pr#{|Ja2$;#SR4~&cE#Bed<^EEY%#AC^U2y2)pJC)47q&;pTk`f@aYk3 zj^|7e53k_M_}6w3d>0JKYwcpxU5IdlT`VM=W|wad7?bSkYr4I}mv?aof3Hkf%U}?{ zx=h?(hMJ2Rud4lV2h{Ap8!QK+R`M1D|9gZ8yN92T!0tySzS96(bHk9|VWwM|5!7@_ z1g}Efmy2tgU{YUkyBJW(W5qqI_>KPd5pNb_dnM>uv9Xf(5bv$xVLq9ul@6QuZWX`z zfMqq0Fz_?U2X0=&FDd-Hqyq!iVG88$B_0@4!B261^~M8TH}cMSdtuZ8#M%)_;dU=VVE12`IPleeV`ANfaCfun@W)qL&j*S@ zyYZyH37QN>iFe|d`mROp4@@#c@f$ub#h-fx7gIdXVsgX=HYV)gyUG2Cbe9Z9ltbuy z=D*Qy$NKu#UqhTeDNw*SBgX;ANeJgez;T}#Tn)7b>ethc9>O*)bFb)&^e}?0zlek8 zBL}ml;rQ|vpZu)9TCvYPFL(zSOpcSXMAL3w?tBF|G~^V@E3o2oeDQx{#JDSzGDW8v zG?(9c8zgM=XC=mpQ>8)f6_~^}zvEsC@TA*Tn(J@v24xIHpOyN#XP{&*V27N(8E%9a z-$7N=!f623r1)mZF^h0N#rr!SmpechKOY0r8nHz>>tFUavO1X+*iRRc4Ck4!`oEZb z2#;6L%Yh6z_oF|LVejILpuyRc3{1>0tfgYKtMs{r3JYhD82ReZv3=fxg3aaAi^P>a z54K26Cm9R*2zZ_FSppHId&1{Va8&sxe3oh4K@=>rEv`e1!3!zq38R6MZj-x$mtBCo zGSg`B2(cau&hZElu-bwwwvrLc`eVt`YH#n5N?Q0Fvgw4PYs%2(|}4A$ARrqjS}!&g}nGW{Ky6Uk8+908TYAuZGhl9ERac9~eSw1&Ha84_B_wh>>JL}d)X;qxjaBV%rj z*iBFMtw%4My?~8iY|i70!mzAfoyK419xhGx0Zmf)8t)cJDSZ3zI69k!~Bl6kSnQvfMo#id3;QG<DO=8v_ z-rY9jDy0!pF$@jSn)thQ6W00eZ?3eqZa(b_{_e7B2vgA;zOd{Vcf#j=h^Wn?gWIsx zfL!$lxb5P|9vnYXVS(;uMC5)^#unA${!}uN z?ze#QTh$-BOm6!UQTQy6<}Y0pTb{*gbF29GvwV>M80b`E?oSb4Jj-L{CNWLURX(NB z!hbK14i(4f4(Xw5Epl+ODMk$2%je-kDi81FBO=g+Qr6cSQY(FCg1z9E>hj5H5kKtZ ziG$%j;qxI`%9w`pV%&3lP&Op%>rE&!FgQ!V zH^jGsOZok%r6hTMz2$^Y8Js@SV+FW_&}vBSeL8i-X)=*U4~lCX*;pF9K6nazt(7rZ z=fzvk@wh;^aMpTseV>d!M9XvBa(ipUXzbRYLmFN0yxac}rR6?`Jz^LIRAn`%9BjZg zubaM4MNX_Zp$uD7H`MSSFsI>(^%5$nHDW-7m|M$l84K!a#eC(@1 z4-Eh};%I4!ZGCXdL8hU=3xi!KKm#fZp6Y;c310LUTP~BgUJIw-t*>*&f zKF@D-Qq1VvHrpQ!7}2xIiAiSW(Syv&7{*C-hz)4-m`^4n@X3?428?D^K5HSvcbqQ9 zyQgGhc3f|YbAN{-2g9j19z8jv?iQbch%IDW9X{gi_oG+lh?Ezx!aXTwzsU2W z%oO!{dEFqdcgkyQXL0sLKFoP@;~E6>ituJSYdX_Tl*}PIp%*!iG?Hw;UUtNSuGRD?M3jJ4O@K}w zn_k67quNAPJh?UnY-`INH99qeAI(>#P)?@s>yMb4tn={#q}LtURGSC4)0^FDx`S6? zf6}I7Y8rHB`!K61j5kOF1$nqbkTd!1gN$nzgp6dHrnCjY9E+@NRCTnhMmBYA7sgIu zQq?e8aaWV*mwYOrs?9PRCG(JM)#e(?Qm)E7h`%^j$~O_;sPY&vS<^=<@1)VJsU8kp z9aBD<_NxkZ;x|#zp*>KltB@*qc_T$C-%L7rlpFlu7frp4)WA~h*Tz)=a3OuNw*CCkW0Qm$2)XnrkZ-UMdr{g1a zd{CZv{tzGNTa4+b+cI(P5bq=TpNmAu%UIK2-XJq(p^Uk~>oP87+jRb${&)U%iZkgE zt-Dvr?%ovF=B65PHifqdtQ0_}Agkl@PMN{oVR z?fntP358lrAyu0jNnula1qaD0G#T1TIk~qX!y1ncnB27OMf!Lg8m~*XN63nr95Y&5 zt&`M=^at3w7h#wq%Tl~Q{afW5@FbR%U~{E`@Vu4r7J5g;fK|ur%-ShZ=kQOnO}LmX|j#MaTe0Alh<~U*y76rETSIxyY<1x=f4t$Ffc2jGwGBYfcqs7(3yle08 zu<42~jMJB#PWYVtnr;G`Cw$I;#lZuf<6jX+4)ZP{XPY3$=G_E5!F=7sgl&{zK+JL( zdJ;m@8$Bm{wnB-1v>C8f41SeIg-p_go9YRt$Z+Ss_k{D)h4Yi)x<%;1MG=pz5BR{g z{+kx@%VBPbdC)`|FZD)o!rhki3DM~_-pe_#l9s59?cJneqlQ;C4A=av)vAAA4b2)} z-KvGt@T7(ZHQcG;CJjq8oUEdg4c7#HH4M_QolCNVUAN{QZ?+MVUUKu->XLWorb40tktkw!)gtaD^&djntPOn z12r^i*t|j2bAF*QuW7hL!&MsQX=v9lPQ%U`Ue*%)Qp0);U(&Ef!}~N`rD2|m3d^hz zcOT8rof&TxJ9v%9Eo; zEoTW^RfTE|&FN}}%vyp>!=10GW&8hx)S>^k5jZ><%2PA?e;b}@C2KvZhHC^msS!0F z)9zTivlPat#wqs=Qir*J#+M2y4fMh52)^j2~T^m$#A~xM6@Y z*(ceaJw7LGOio&=)_+pdCTEOEn>}W{EiF6kjvS`BC*3h7WsD74vx_PdNLAD&D7Ni4 zDREPx`;K#v1dq~eE-25Yu)JaFsNwO$^E1Qd6RU?`eFwi_$S))C7x4R{&F{cHH!1fU z3@svfh%yE+VTdvW7Bd@$C=&s2brsD+6tkgB7?PCffSF0kl$iRb6;_t2u-%}Jzk2aO zk}@RBo!;hEm!_~tn{t0_)b^o@QLGxK1PSv{C31VRV)n5jLuKN~%}SWC4^_;5@leK~ zp(zKO;q?5zpoW;xnN&g9GsqsoqAH~zwi$v3 z1VQWe#OFopSS=4-?@uraE3)NhZOiiz#TdE(8lGRhM>|Y348tA7lONpyg{C_+ED%07 zE4@3@t>}M|HZlBW1^=3D6N`o@-TZCHQVWW(M!o$VH!G1M{$^R)h^@P!S)4^Qh6aIu z7wQ))lhLBfo|roEft};ujYx>id?l}2{q}ETtGHO1tV|5<4;3Q%^%0*XE0&~M&IXs{ zmzBgVDI{rQ9cNacM;4cmz${1bZ)JG$QDtQ;;lQ9%XnFk8!WXBy2o=2Azbg87v&Ld(@in1#T+CkaS zj=;qNGIpvZ@1sXVkI~9-KI3&UZM2d|c;9Gc7Ul1!(aI1zg2hinu$ypM4(isanS!x5 zIGbh0WpHo048dj17~&?=Wj;Aq5LZc;hsgO9afja!%f=`>46liRRHX+cc0;NHz_63`H7$7L4B{g#`uJ`{Mi7%5W=SEg#<4$H3|m=^Cp#z9tY#nlh>f za%)47_zAd70r5`TA@Y5gE%C!fwpg5|^yx{7RKxELGZJ|S%qyUP0E)0Ev97;(E=|ek zOiC?~k3-eO8zw8vBm&Zv!BO`8j6DG|Llg@?uUkw=SGqc>HtX{zAy;M!Li>-`#IkyF$=(z~Mu`m*i@f9~68EK(9U z8l_k?R_W$sb&TBw%GAQ>-BB?%UApHOoS&3;Z^U3j(!diHIAtS=Qm6$rnSi8XL%>;AbI`7Sl zvnk!8YTst8-#d&A%+(6O;})xJN>3-Xgq`qu9@P{71eiS_E}M(P7-i%)nb3J-kZ;3Z z24f>HqWi6-s_bfHUGx4ln36azf`Q(rp#79YPhZw^!8I0s`6{aPnt|k@unepxKeVV0 z?sV2JFvB4_0y6|=h@2q;)-eHw-a~$RxtNoogbk&fLJl_|@A!^j*FAGGkM4I+RM`%=oNOp4!z(R`EOPLyNDYTOTf}htF^pgihzv zh|$EZ>vXaaUO^*lG1UISSa<9_?$RRky2X#TE0%s3CrvXjbcW(G0A!MN+bjp#6m_7j zhC?J}Dg#q2KKM@ukQIut;YJpI&WJu4AY}(3&m=i2igfgDZ#eO2CWa@kQ>xSOptc1|3IfhZl_nE4VulR1G zE8YFuoK_4f;Y$ zw7nY@pw|(D?8=CtX1sei3uJXrJ~3Ec_J^8@wU=X#*Xf0dn`S88yH%s24j2avMKpS)nBH4~g0;D@2 z!@xcw8IozI!(gTW9hQT;PBOLmiJP)9j5(0srJ#XxwH&r{tL3TJG0>EZDI3kWC^pi_ zBF~xRv~5SWw}6T$9%@aPvB~{0Xq6UsdpELm&V=3vMTU95T?D#_Em`<$7?3_r9(?icrW&X2X1p&@v5#A*b&$zsRHM?hsV2-**V zuo7R^UXI@D(G%|?*wBUv1{Rr(|KyRuu%Kz@)+z-h$VU}AINI%G_a5b23C@%Rlm+1)x(#Cp-}# zK($&}uUq_*qx6ePScpI60bSI*y>7f+s&v1#VUdCT02-LzR_o**x){q5k|CvzZf_V- zIZ5dmR z7b4wfAY0{;<#b}?{sXj)WQeAto8s_>p%zzSX5P5PUsKQttMTvEwV-BCv{>4b`*To> z7HvoO^hb8H)Z=M9+>eN4 zX}&7n&Q*rTV0V)hff{83>WJZ$iP)*iZ8u?~ll1{5EL8K*-i;oG-o)sWCmua<|5QcH z#r`K-4r-xbG^SiOO7|m>u|=BfoDU=SQBWMoko%5qio+WQ{%!G!&C`^@w_qEUeGA$q z!{ZKed|5jgE#WcF1?HjS>;1$p)0BRr%ynqJpmUz!$fjNv6@o5^pdl#4ki2xQHFAikWT z^p1w8g_I3TuzUpZfabXdR&M;5^N&Q#Or^Vgib#UbW2mtBTft<4jOe4ZP8*G`nmbb& z7)y(-a(K+e4aZl4*#R=i$Q%jDr1r#2CB8e7I|h&VcX9awq{X9en4*uS_#b>jXo^l<28A0EGm(0;$OGThV=|!~=SA<*+ z!euzf7{u_EJOdw9a9r3NN}n7k5IOhfji0K2(X~IZEFs?2NN&&&=Vpjyq_ z>lVMwQEr>o5XIS#prB$kwB8*W6~LmB%q%K9qB*QFv>~J}xG2aGXs1S50R8wBPy;xwge}iA0Pm$3<8#n3`Av0i}r=6*D z16kuh&cq!F$e430P3ZIkeniP#&?##^1of?B00_sdfehy#UG7Te_5y?7gvVVawmZ+TwD{|kJ z16ehHC{Q%aQ=(@X0g3B8g?# z^npJk15^03>-^Dwy!zrQmPYi5xEn#^_u+C-%?QSo8e@Nj??MJcqk~v9Rus`#K}2J1 z7M&g0+@&$Rp>v&CP7voP?2ouymSL$b8hmfU2*_Vzp|bm!+D$0orO=PTB@TqTGt3ol z<|!7+hD~~5l`{d1?LcCXWkiczowR>+JA zYE!f0R6yOWTf&Sv%UJmo&K?0dcTj}1&2g@PnevLIa8xd5dt^eGtD&TKdje9p(C7e^ zO$3X6{`&3_y#n{!2bUor>`S41ti$QLmYZgB{;WS+=5PGiM|7R9#7v-;u>g9#Pml7) zkj0Y>$&$a`-7XA0=bl4S2&b1v;s4}~qj4u_7dsG-;}KkVvN(FDg8!Pmi?eJ{jZ6Ro zD2k)K42?jqGr-6OU_Immz2>{I%Yu*D=)<;`VJA(mqYG-rPUk-@-kQs_iQ@_w-&!`3 z-@!s-Oe`kPBnB*0I?-AwdL`N?O@Vzx`a-2Qi84K+Nn*u9W%MA&2F^YKl|U~0+~rQJ zy$nlLkB&HxSkl;Li~vM32--k9H>&)y8C8zm=yr0{q+TYn79pydEu0lraW?R7wKcVO zBdU)u-W>~P?d24eP9|PNR5v9&z}aJX3xkXwtM=4?Aip8~me zgDz`9I=a1K#LNPvdta0>O`~|@3mvByV~?RC$-VV?&Z1u6EcpbXc(_36;S7!RVUcsg z8#@<;I?M@ey31eW>`{;%y7cppG_lA$GmA_LVUZ7nH+OC{7kT1sfZiXVRnR4rGwNu? z&JkZ|vvYc8L-e7ztK7*WfTa0v|kkaf#9oC+KGhYJ^Xr za-*|lb^8cnfX3EL7c*zrVE?^Svdu6Q)JnYF=S@9POk*A7UEhC& z^wPq46fmu@q=OjCl%7xs4M_^NUy7^NZ&%EnYIGa9;kHrKN?GN-SxQDJ?EW3|hn)d9064 zibBYrlLsODRlM$0q6|w9eCAYMH@vh?*%Bc3Y*EU^mMx0qz`!bHx5+v3NjzIj!t@9X zdk!l%@D|`WSdW|r@3kD6tVoNJ(J&RUfG2z#lnh>PE<$D`1u*}}gPd?Hs0_T`#6xEe z;*@qGgJIlJ3nju~pnC9xcF<|?gm;77;0bquj8ibz0zF0{giWvGW*{fL0vZXP)wLOc zkTJ+G7eQ#eV7{2eEl??HKRGy@A@W>ErOZ%v^$wICCWzA%Akgbv{_ z&^7Rc6F@;z@w^Ot02B?L@F>U%-fJoWo=hkXeu*|)1P3u6fvUkb0%x4Z!vuJ}Sp=C& z{0O=RIU$)tm|>UTHH(0p%q4CGSs*9;unAiZ;PrM7dYcH?MmX6wKj5yRM0n{UW98rp z{{&To*V{Pg3?QUo1pkS#!_Xn@+>GTIc*5?WM(|$S2V{z+7L8ieI z`Z=$n=;1H}yTc0M9C)v30qhC%mI-8`Q08Y~4#){tgUY}YR)98vC)^9#0iN({(0=gE zz_dV|>VdZdSHa}q8h9t!9-If!*-JC70f7gTs5|4_+kmPj&(?fJTBR46>sNz!QdPJYf{bxd0ws3jpwB zF)$HF{+qxPP6O3|Cv<=gf+w7>$%}w*f(B-zcK|)61BCl0;#?Q{gfD}d!4uYj7*6Ja zPWIc7nDO` zfhR$E;PFle8v&x;Q3Tuo3d(fCBM%-R@~8#wxKriz<_Tn`Faop%5fSEsYQTHV4#1N+ zLf}GF6?npU&==snwg=$JCZTQ-#vAa2C!M%N!$!bsT>xHhc|aBkw-%r;LoN|~9(X%& zGN=T+*Yp59nI!lx!RQH|Faop(yx0B!JlQ35Dn#Pooy7D4or5C**kh@IU8VrQzROY6 z*nm#}-hH=PHRZsn)#!4NR|7v-qskkBBi5?C75FJA4?1|ahfP_Bi3&X4?_qt{ql76= z;6oLt|6Oq41s-+SJS-t%FbKs1EoT_5JwczZSae>4mo>`?L=H-Oh0Kj;l3$YA22K;MN9 z;jf^>;0eVJ6e)PZs)tbb;PuuHdP@khkl64rGVO%*0Wtpq#epZ>1xf<1w`S0rKQzNX z>z~vJu}A@~1r>lNd>*t4JmEo5HF&)5#U}4Wg9VRwz1T1R12Zh}WbNSem_QId0=ftf z!r({IM`6G~xLo52-_v-!495O^0`moQy!H>^$zI~CCt19;#~G8XY1=5z2C;JJM$4e-st=tJl_BnM`{j5z{)n?(ey{vq>NOXw{r z$igD$6%5-jb091PWr8Pcc?I=91CACrOox#>@OWK~4To99D)4%93Np30$JCaOce7a2n`n&i!24J1 zRS;RH;2kXN*Qz|;!(v~7aw%|qo6!XsU--O(OhZms1lk3j@HB{~=0;%XyJ{EpSXMa6 zBtvg@LFN~;-@~{KIpIpsMeu|*pljd>XS|Q$6IK)s;1v+9h*$&K$|<$qmjf4kXkZrT z6ai;^gb9iCfmcCg;MvFM|1W%u5ekkvVBb%XTkr`$-$rx~SVWkCzkY)Vz_V`+?3MGl zGw^yV39_CT`8^tJp(1ex_(<>$;HV2IYVcOzxSxw)&Vu1jEZad9&>`ID#APQO8-b63 z_JAjR8FUzY9dP;I7+AoU1217S99A6I+{dXl>}rHOzeA< zfG1oDssZmcD*#XC2A_4|>@ax3b6vQTor9wpj$<%3xC~xzXg~%CjWIX~!RbHY*PxN$ zn}OSUz+~cfR0r^AY zgu?;mWI70Z18}wtb%t5a0W8c!72qhn?U)|MNI2dvwc`v2a>9L}T=0ZPKxL#449Uhu zKX@~6|3uU`_&VUzIWYePUkh~RPr_Lm4y}uTeI~2C{=}S4*MA2&phLK13hEd<;WE%B z@cP4V{lPdLkawMms)Y_=BIpb7ggKy#rC9$vz)W=@NAPd}A6v?qbp>(-q~HnHfoj0(Pq67EdmfIWPeM*u4mt;(@L|wp@Pv<+p#I52f7Yx&pQdx_ z9V<}Zcj0UXSOc%WDXb@#We-w># zYnHwm^&bZ%Vy1ycf+t)EvV+$jM$=jKvNgD4$O$)q%D@wD18o7XKY*sg>g_1qosbhg z4cZT$@DQjTe4P{he@Qv+7>**~{cCXtD-jX!qjhME;2VK-oIC@(_gEP`9YH(pMH?YG z@G(#gc)~NF{oosczf@xUz;auEwoGTyU0g_aCB}bZo(DA}0O86l$i&^4@qlYUk>Cj* z0FjRVWSLH)gYQFwg%05dpj_~T_ilyt26)2zK;_^G{|O?U8enhd1L~c5&zRvsXVN!5 zh`Rw#xB^rMo^T83H27*@<95_Nc*27_V7`X-Q3w2PC+3KI&{lw#YH;`9*`u62^f*d1 z8wmry!y$GOq(qSf+ze9 zbQnC_&Dofz&=tYkf%9;NeGa^KUhR~J-1@_8I^^!X2c{#d6p6P!i#q^M_!(#*_(tH~ zy|@F^Yc25Tb7;JfHvr$RReMS!(6A3h4Y?6$1<~_`4Y*w6OZK59J_`qJli*{2?26`b z4Y=`nHNYmIX%Aew>+ z$ufs{GA>#PBAr#hPeI!dmTZ}()L}dTUj#e?I=C9+e>0d%piS_=CoWhQP&IgZ35ni7 z%EQ(iVedCpo{R~PfXL{atQg2TVHHY9B6yOM6#^L)T!fsEj0Q+f*hk|NfDhOAS94ke zhwob|Zw9W=_;TQPDt{pMHT<#Tfljr`8K20Sr|X|?c{=hL+cRa))IQVvO#GhQJ!Ba0 Fe*mAOTaf?& delta 58259 zcmaHU34Be*`}dtmB0=JY2oWSfLhK=y5FsJq+_YEx#Gou zg!y>-A03dO;yF(a7|Zdj{AVwXuJWH>jkRj|!3p$yYwXAbs>4wBUt>eB7=vNdoN|U% z4;sf8 zCm_V+tTPq=4KNtun@t`yB58!d5Re1tY0&J)Ge`8`4H~98AzAV-67Xh;I`wovz)^=G z0MAUZiZ@_e#UcFtF6$1j!WM_PwO4E&19x#l{`D`p;W+*wznk)>OY${#BcD@}|A6va zzZC7A*YnRl7dM<|x#vxAGAK54V1T{d=B)Qz+B@^}E5*k0ON>z~xj|9Qfzy@H1JN*{9X2h9|KoYEcc4xtA+T@>ld~*E4ykCW2?ng@0WaSX4che zevGXYFREYQUoRBreBLVm*v1WJ+mOI`aa#HcQ;n7G7kr%zQ#wC14s7jQQ#_~_hoT%8wIiz8zUTvER2XbBJfY57;N-cFiW-Nfk9~&2qXipUXPFteW_) zmWj`vFaE3bDc@)npVSVjnrfwLW0+!fQq*4*^@#nc6lZFWVN$gBOX5rBiLHKh1Kytp zD)nB0Q%vY%vwBFePVqE>+B(C>q@J{2S|%R&wc&l{Wi|32$#~Wru_&M}Uo=N#1%y=n zm^iz+nQT4W;u;?Ym;Lg`;z>YT-eXQyNS!doFQ$ueb?fr&>0)8s+nl9~ne`m}K&qG( zSeLI!6`uzl;MGz^LeK+#D@6>c@5c|Nh>z+Au|?wZ`mMaaO5uhAABXqU)fgj+dcpq3 zLXltp51wohCmPh{y)EK?gJwq3t$NU;o-?VZ>?>`eS#U@lKMOePI=t^-7-*b>%21hY z!V)a_xLH|M8}{M+;tVmaaVxe;tZux4Efq?Wi)?#Vou)r9_FvZZX4^SavX-{E#jA{{ z%rK~q?Fq)HR@9pI`;&#ORZV_wviQ2yVSZ|o__<9Dv7q%x-g}a`-})M#ln6*NdnWF+ zt}ceP{ecHg)JWQfjl_66-Nq*?E9{gr8zj;q-r}xL#4i!OQE|hL%Q&koaw5OvZLf+k zQ3c&%ub@7g$KD^g!M^G*heP#JY~9`Mp*r{gf#(*3tJ-Vn;DZECEC$!IyIc{UbZ*Hi zi{qWM*+7xrC7Z1k9il&D?`K_%j^VssJY@3`ZM*%*V~0chYFU+(UW|)>K*79{j#br~6hKHV)#r7M@4Jk8f7?RE^>cV&zgF(}nz0*+9DYkyYX|GYcmZshX z8>Ca;8zL5hI`}o}T|-KhJsl=Sr(QcmTm|)|XJsWBTbi28mrniG5YeQ2gND}EsB4s_ zCOfH9^C9A+?hUH6dyV?&V6mfnApc^p__e#zaQD-)HJb*PlG9$bxU80gh1uM;%D~sC z^9PBg=0Kh|C~L3zw~B12_-w#vHbn4&tMT{qf#GbhxHj+%{%#xe1;$I?!4vRz|KOGA z$oL@&{%*wI0pfx7H+*P!q~{Lp!}^OWLvOL4MBcDW)=u;pzJ*zZbNo5BU0jO4z^;m| zBc`!;MesYR><_W&o%#H)E~4$o1FW}rG4gYEN30(83G0KuwM5@{XYxJ6#hOty#oc!o z@XC5}`RD~aVVDMu8Z(#0iKAn_=jDcG%}e-%^XK8B-grBo6fQg_3^P^^*X?m6+2eKX z#fKAibC32S^S$%Z^EUxaBW^KOy){t@0XOqeG| z@P}=MI?<1xZ7ViS?8#HxiWdNOX)D4L{oLxcL=!*LMtqYP!9^QUkm$#! zv=J32&EX>Z_>zBh@2w=U=R7Fr<7~!I0#ps6W{YE(($KJKxYkOid1Akzz%1Sk+G4kdc#I z71q~aQZFd5O#NC3dvX)6HxU;^gQ-pb2Yja(^FQH-#QLcUI`7`p`d%I1sODeMa9VBF zQFNQ;&qsF_3DZoxW@nK#Eyye44cf_~U|Pff0pBSaOmF%>;1|T0{|Wy}te@V3br6@P zA7Zz~nh)Bt9pd5#8<@M8{b3k8EB4^;r{W?0Ld7$#)ZE?#>WkRX2(ve-o}%`QRBTHF zFgfkdw}^Tlo#J1AE&lze4+|5fnTOa+;W?`i>dY5YzrAe5c4x zZ7OcguELgyCrAaRR$-4t+q9-)6jHauG^Ez0R^g))#ICd^;wFF~1TZiSz+@4Y9_ZEL z4e4HriRn8k5BQm3eLGBEPKctOwcADOjFnaX#yC>c1%Z*UQZ%L7*AX`}-iF4*=7iwy z*f}-%^mSQt=B(ko&8DniYXsxJ))HgpH|Jm163gc|V!^H4&Kao0ZA2i=!h=OyY+SXu@kj4fW z#UZ(z&-zWoFZX71#nk2VQ7QYR1^$M95>#v5Vp{CsI9)V_A2MddI2;bew(vCUfPJG# z`lM5hrzeUDl<>pJ*MQ6{1c_WS)CObm*Fs`heB+V%@S<%bTw9v4h%4Q_VhGX zMrTH;TSBnfDH*qo>0f{|&XyfkjvlS!H&`?yP<8(oJDAVCx85Abfk60U$c5|CS*#95H^+r%KM9D}% zLrv=3doXb(b&JtbYK_>;ZA-dobCV; z1Kya!I}vPV>*z>D?GdbG98Gc$J>&3x-b6h3v>}TZwLYsSB0sC&YFQ1`-T1n(;r77O z*o!EtOJE@&p$8OeMvl>d;s3j0>zk;krbxSQCZ>bUrJnfoGlf@B#m&#^^A6R8`-)vW zwVF7zq6gnsUQ}CImoG0b+OMp`3dE3=Z5sRpIU%5zdK!LIUyL}rU3EC}XF~rD@0ImY znR?OTy+XvVswK{^>;fZRV^wRfYb%*SEp&K44k{ve6eLEhYRdYFMXO?JCI*v=&4FPK z@2f~UyvG!ijTU!Twe;+MkpUP~3=9-4R!?KC#KzV2_?iadhPc8;U7Zd6#J^_ z4u`RS&O^o6=ui>R({3#Sno5B8>`4Hk89UxbGkmO+?yD$iGvhrKV;7|0C=%x7JPqRs zOt6OW1m-AVZt9qO7NFcT)IFdM6Y3`o<#B`3KTulj8v@)z%5T>5VaPj8M1B?WYG2rH zkE)biq-CR#4WeucQKQpHLy`6+^R-?J1x5!Rw@>sH&DXYdn-vHT-M+>}yuY@qTZoo< z%SG%%=8t-Wadr_EKCj8w2Z;uscc{P78Gd~rMw!jy<$I{5#$1P^V5P%*EYSkkdjf#Y z!uok=?O+Y0UZ7n;G}tipX)MvyKkpJiiEPGUgr#Y1~Bz zDvFw)7GZscb;+21fhMYL_g0#XHjm1~QA-ms;)|-~{3%&Q%=jYIQjLch=18A!bdP<;C1gfhp#r~Pd%8_Pz>ts1P$csQ7MbCAOEu4}bS_QFM1*1?J zHd?PZ@26`OU{^?>nnZq02W9G@5CR?3LCbZJjl|fcgVqozzU;(L`-`q$*7Zx8LIb8xV6c+*QD7tuOG?{3&QZ~>V$PTC%Ll?qIBxIC zxH$S{7fT``W~4bBuHn&e>w~wS)%mDyD$jiGIE6aRr%O? zMEfumv}t*6%IxPyKr{J5T0}jqG#Knt_N8As94QgY9MFm}eYie=T41AL-$!gVj|fU{ zO%>O^s^J<(>C9B|@+;qRNtB)_{MNT@cn*6Bds~o4s|$V$aWlX(P5-S4p6bWH1>=EI zekPKt;)C^mu8$~rZ?;&qzGb6Pl+K=A#EF$pQncLA9Gk&+Hb|ei3N(wIn=4jYlB&hgvRcs|>n?t9uidrqB5p+(&m`Qiv*DM z7j3={bu2$pLv-C_f>W5eDVB8>ziu+~KYc{QZ~S3dP2bdn z&-m^)b%IRyi)w!sIi-5EnuFROjwWk;!Cvr@!(qmP6|4xyZeMZmo2|ZsFzH{(O5VE7 z!whP>V}@AtZ5vC4H_?HF-ZF!RNT0v}EN+qZ-n*HhpiWxEmAfT{Rne<%R#f#YFr-9u z!qR3)G7%FE_eA^LnOK@_3w7Ht)*u;Rgf>^> ztqa8mn*+JyrdYkXslSs(Tcp&1`usGH0`d9}vE(VjoZpx~_RjLzQk^yO$YyYy{T`D@ z{<;MQFJ;E|}ct^TlakAR+iU^&d`@L_pyJ2XM9u4xfd z{wZnw4n%CA%9R69wGWo8f_0@SO{FM5()oXaYfQl<>O1?gK z8jc`aJ|Qq(QIi4_l(Ykp!}F7c&v(K6c$KWq-wkBlTK!!jM29#v7echrn9kcTBt;yEaAUB)OTinDT&VNBlgfR(ANxjtlm9%)Y^8c?`iw9$<&8^;qYkvXdfiW+{A2%R!`FM796J@P;4%vDr?gMhKhgz z_VkmlE9m^q5^WX@y-sABK1`&Ev@THi?ry-x-xghVH)hSm#NCYo+Grd_y>?RXH46r! z{qjT%!0(xe%Ws7J#m(LSHQe+QO^FHU<}%}Nd*W;3&r4L;8`NpdA0?u+LPvdxLJP2g zEa}Zzr6{T(DhQ&0K{Q@2*aO}dmV#<5rmml?=Iuz7SM z$afmVS%<_CWQ_)K(;*`XvXDwpmwD=-=>(dggM4&Q27wZEP=F3v0?-(HUmX^#!`2g7 zXB`xxgZ2@qxef}`K|d3ymJW*4LAMB0UI!^U=sAHNPoPCDRIJ<=W^vFA{0;z3A1%;w zB`qgFvDHdZa&I^*PS;c~yCC%2&S*Q~?de+94cS=ACL^n;Z<7c44&~p~^FGK=rhH#L zk1{<{DIcTfY5D$iU225ugx-d3ME9wdr8dMjcz>>y&S-=cx^al&`7hsSTdghKeHfhtBR{k1@10 zgL3kmIQ>IQ-xJqLS(II_+W4#12lSIftsm!;sra!AYbgqT?8*zAMQDz~*E)-tISPV% zhjL8JLwM$zc%G9OoU5=8#JXG)YcB2p^d}eX_AC4|F4FcZ2ZTAqnx29C%x zvB_dnUMzO|kMm;r6@%z}z{D1d1qWhT8}Z8lQ^-FKiaQh*nWEk$rsxnt?c~@L@&e-R{^I4)P`|9_j1Dl)(=O)J6=)4HpRF{{;gk)(B6|MRocRgM zPt9u9JzJ_>)Ae?ZS5V=hVdBV7ZJEcCW2R0upEB~n%d1Bm-mXYv%M{luCNyUcJU)m0 zAXXAZJ)v!d8L$Oa%b>s7BIX^d)nMyo%s1pG$A>RHFj%_K2A>RI$ICku1?Q%bt zbPvoiHo6}35QZc_Y{L+7>-dnN<1T@5_5nMZ6g6yk8DC=Z=@RB@*z$M!4;s>3irOf{ z?m2|a0PPW=8mC=YS>V}Wf|d-97Gm{@YOWJwL40Pg*mok>-RCdVrcJ)h2gSV;Eq%W| zRZ43a`f~m_8VtQfhm(m2QG9zcn&E)%WH)}}kqAGf@J}9zj8i7oL!3Gl%bbMo=~%w& zUorZ$iM=Pb;xF9P)26ydAJXK}*70~_Mon$<#LX*N#*c0n@BSRu_Hzu9S4;MFd%?g` zTI_q>-hCD|aS?4DqiELw6_bCMF7kgK{Fc2B5y!2GR*xuFbJ2S4F|JTo5+DJj7{256 zDf9NR615hs=jX{p7xoj&&NSuuXT`xY?c87fUaYB)b3}!+t$j0pDy69_IMYF2Ug`wC zR$}1UST-4j#J#jsIg_qndD_LB2m`GvbeIUj?=y@lty z!c#wg{#}0Nj_7cq1$QW7;)RaPA~s(zw;hO1A$P#m7yV7qgSBX?$%cWi`4W8%cEbmV zQ2{`j(PE>0H`qIf7Qc+dxyRC9>aa|a{Yy-hke<{D56$WwbK?Std-{Q>bTQJ?Z;Qi$ z=$f07c9#Ka5yLL_Y(E@+NwYZ?ISJ5m@J|Ws&@`Haj;8M$=m;SV5nq3)_){k`x#TUp8QP z{%<|SmP-v-o2*|h)nI<^<7vhk(>J2`_1#1xR7?I$Y7d7)7;ja#e7(O!v?*wizfMr9 z$QY28o*2_haYX69_lISL@Oq7-Ybg#)FpuXrcpxDP;v8b#uWf=J<(6vKRjr#mI^qzf zln{&J#KfDy%$^l|#gkc*#$kMwnyYhj$~IyGrZ`DfqL;envW@6lile9z{ma&PuX|aJ zdLme{B#J zhojf}@VkFz`TrKgEYs0X>F6gL%~G|yr`Z-A7_x`vtV2X1@=-9YbZduxU((uP5M+LP zII?l2DZ)!pbkH5yh*rAgysErDr7L~!Q&Ju^YzE3BBb%j&U$6JB_r<<98}?6&QVr{* zi00QKc*+fG84tW6e!BKHKlO*+v;hhK@1`klG%aFJi73>xztJaUn^vhdx}FS1M7fiy+q(%1HAeS?{-)meJHR(y@AV<{%;qrIr6 z9L=E{oyDeGodW;dSxS`O^eNP=iQbY#48dN*^DUy%U+`zHW`+Ib%&ihZjQf+{@LyJTKLhtsjqFa6lU;1m-2l=(NK3M*DZGQKn$o{*lWi{gDDG|N)g4~!s z1${vN5Uq3}_K$JARmv#}u|FJz0rFO9KkMV~O4{E}4>bMYhZ@^;q@h%ra$G6OqL9=& zj5}_}Hoc%aufA8vf?$4iy~r&H@xQjMR7MpVUTCl>h`albqBjpOlDOyU-a)Qxz?iKpoMnBRLzT z0zx)8*abKb$5=p&ib6llww81RrZxF`Ay626*QWN<;jhnYR*JeP>@uS{)caMqxOCgE z@>jc1-|PdKx?4Cj@3?Ti)5CY%mQtOvu!7bpS%KiHBqrV&iwNMQJMZzG=Y?{&6~EqG z%(|PxU!GfXFBHLsR`*7;cf@D+Vi2PF{a!Tx<*aCMKbo&SE8e@`g_*^+`!TFs)|2~# z7~7Qf*266fcP;p%R2D8W9yN8nOg(=vRP25f)@m@$V{x=!(S#skFU1<;Q=o3dEDM( z?rHMhv_qwTPm4W|8`V_Wfmn4@tdo55ml7i#X^>YmJViJj2QfDh^dz|5&hX3pXn8}8y;Zeh)hDHq;K5S^7eP44rciGuo_&jYMFnwLAp2dk7O}E?{ z7(HnRg0b*c6JwqRv-h$xpH^pl$46r0vs}JplbG;4uxInnONJe03`HF2FvxzcDTZ85 z=>h6eigKGyISrK53>=?n^{j3xetX`Cr%6%qMJ@jETG8-Dt!f{xEhXDgUADYxV(^Ow z?8B_I7mHy|Xlno-yKu`!X?#S>7J z+3hzlJu}mPr7H-1;CkEQw%WV)40bruF}0(9{0}2KKT+G|*bHE?ZyJlys@U|*<~edP zXH6}0zrgmbDXu1@_)_JzNTU2H7)>Yw*=$>J$YO60Mu|>+P$F5y!UGWM30UBk%rN7o)ep9p*f(0yOhHtsT;w~;ck=5nZp$~ zO{t#1{f*(CY%gett4orjss?x9xNx`|ANY_x=?v>;ZKa|+n|24E#iAj zD6P8U12c@5*&tO^kI8t*S{mX%Q!+{MUsw4yi#7rLAwKeO(na*yfR67g8zpDBU*`i^m4-;2uNL<5$8olRe9^ zu>NsB!phhuu7Qc+p}!&uC3RKfm}&q>ml5gDb?Jf!h00b_c0aPk%I&%W76**Q`JI`h zpc~8NwQ{V6Yf}#Ll)Ca|Io6&ZSS{PTGJobI2f4C{o)KsiB2udv&Ppe``~rUx^Dl$$ z+8oNr#9!*aUNje)Bxu!nQaT3;0UU82oMDgA(wUUrFk0SnWnJ2A`ko3sv5Mj9&fx-I zNIcLV%Nosu5G3rObsUaeG*vP8PB%my2#R%DC5OAQ1m1d;4De;u`M>+*A8xFL<%9Xq zC!Ora6e_mbn?B}-w20;SYnbIvS7*{9wje_~^D=^ z*`gu~?YI0h5}72v0C+(=hxahTqq1Sd^t3jH{STNs&^r-rBciI>vA%}C^a`)txQZ*J ze!2On+*6U&al2pm(sA5gP)pvZ$eOU3($k%FV?lC&JI2(WYVu=u*2+1(n!_P;DlzY1 zSYQb69aft}CZ}h0v7 zFTKjjuQ>fnIN^I2N!zH1^8p}sGjaOY`G!0QX~~Q-y`H zZ{_tWEYkg-Z44BZFnRMA%h_J6k?iNiJgfDCWy&7_xjMjU!nGJf%ba;GQSu`%7=~w7 znd8N(@jtBcq8E$u|I7;7FVRUvi)ja1{8OG;L3T|5=p zx*EeKN2XL`)gpFdxxwuge{|p58ol>NRG3!mI7(^7;$@km_QtKWVuxsCxcOK+R-UcK z1_l-`MCo)PDEx9#4W;oj3Q^+@rh7@r7Z%E1)mbE;ut+Yc&SGi>Ez%dxl`uh?<9aA2 z2U6e)>s}}MusUmJ+3+om`=1u#Mj}p0;ylTw4nfXrTM-z5=EK>?Ydcf$&d!VgIQ&EN zjQ)o8e$4O$zgGUtkci(F{JPa;24^q~$8QgQ#yZTf1ix~CQ<~nzD*i{uJZ}A!w0{B= zxygrh;#C&Pe|%Uko@0|8Yq099zwB3owd3#E;W7{ICdCmeGE!HNW94 zXZW!ebwk{_;Q`&g4X_`qKx68FLO$oyYv^;N^S4%zC;eDIzGAMd@6YPio<0`{^`hnz zsnyVlX0@xEx$%Dc9T*_dA}B=m48WT6&Rn^|pEYrF|B5>454F@KnZjsezJq z{kmdR3TdaC=kQ*Kv3Q(rP^NTczT7@b{((~r*N!G^f&ZE%{ezizeIo{? zV)a+j4r6W?y-;-kV(dd9TACae%=~Mg!X{dwu@3A*Wz#DHd*>@J9dcDL zt5@;unKUt>S~qM5 zK9U0)vPQM7I^T7r-AwRR*ZIxaV$nN2sXe!MJ2TxgTs;-V9CJ z19)g<<>+N?njt4QV)6XhMR~3ftHY+r$Bozv?mI*N+nB9jL*(Kntf}|fc@%iWtvp+t zTU=ut)L*bKoJWJOrE3T32mYaSZ_2{l)-0!Sy5zYuH)ZxZ3Jz8s-W8SsX10#Px#3}$ zX|&9++lP8~=5*P&8QaIFxya@%+1uHpo3nqIeMLrzHO4M)0&-fTKH|e>t;p{?u!gL@ z{Hp^S$>)rf<_K1ozcW@QMzDacN!Wrz$M511hwmTzV6UEzYy( zea4l5Vm%2ZC}vAIxZBDL5v*yS-(eb#+nvS&Z*%uoa&I})_Pv+l^iZ+3zBz^}I!NOi zyX6TO}A3DNRG3B4R`G>AqZ4b&zRu3-#6D$iJ^v=?{Zt)#IXf+iJz}9r zH)ub4DD;fE@j<-nY0ACs1gY)zofD~fUU<=yh7GCV`$+_u5Evr;17J9tjFf+Lfn~ce zn_7G1rmPkX8`b9>IV+mQH1U8pfoTf!h|&+n+T7b>)P-KVTqP!ao zEA{sX85qM_cq~ex@@C(lX3voC#4r;dF+zSD!$K-|iZANS%W-4@yc@_nF|dGMvPxH2 z%R%vSdRKI5n|QgREAw-EXELnl^?`KIB_5{$JzSbiIKc#8us5Jf2~YyYF};BVw<94|b{&H8*+@OpdLcQaaF(k_CJGP@ZJz2CMF!{ka@JlGX9ZECS(v`iW2E zCnH%yKB&ArFcLE?sJwhSk_CCZbbG~B@RMvj3feyHCVPxx-9qM;pjI3ts$++o%hf&9 z1*h{L71FLAW)6Kn4L#70*$2AGgQHk;9_%I`k7AwOZ@TIQBLFf&M!(CtHCzk`4(%Wy z-G+9;q(5Ze)03#m6g19NZhw~rxpyfl0PP8rf4*J!k3Q#mXce;m!~hJ+WhlrApXe(njits>r1 z|MXu<;gp5O=E_d8@)*{e?{Sf%#$X6+uPBF&gZH_44D)gy>_WBEit3#%PmF=#Y3d^H zk74cI@8g3CMVR`sZ2~ZP&V=!j?Z5jxT^esFtasGRk>{}hF@3-`rCu@{#X=T!AVvf$AX-0a3&{BU;+HP8#SS= z`&|C2D0jJb9EuvqsgkPl(m2Rivjn~FfUGnge#LDWGM0JEnDG!1hhW7m>>xiF&+4+- zI(FN5*2p*N6}E@lA!pZ_irUXdar|UAxync5S)hm0E4=seJXwDNtK)Ruz+~(M7U;AY z2~AM+q?o|MJbD{mRdr#%ya-}m&!9_cd=H}h>7bpK)(!8=F7H8)5~EgP;{(Vap2Yb%jxf99UA;n=DiPX_HkzN-XvB} zR+`AXJf8peN`f^xve`uF^7w!9t%)qc!&ZWN@S|KosA2!foQbTRd%Y6W0O^v*>hXVH z$VQ2*oyTtNje4y`FMp7UiC~)lLVldc!rkLaP+a~>OnxtxO=9)=m1AMM-(k}^v?pmRY zOo9R0SSXW|Sbg`|g|9UBzFeP#0^cf>$CFq%_b!y>lc8~!m$F?l3-jIdM5mE1wNsiTr!(AfF4dx0Opd_QJ}J9wVP?<#)wBG@HtChOqmhMzZnr|~10H(c_kc>aao zef&I;_gLm!)*@cEEFfp~w4_KG3V z>a|$4Ll~~%sf}#?;0ojYu4r42;Hb10%$Q+C+$`g$y5FSsOaObXlKZ<$tm+(QR;x1g zWL$>x8N4?=_9AEVty8!+&pz8HHlO4zHU)FdcSH1MYI*iQ6=r~03u8Nn;5B7Mb)K?v$;1{ z)NcYepy)XDfLT8{I!}A`0DI~wTGKw(nvwS5C}{Q@kl~Fnt+7#iNDa_YrI?JPQR@Dv zUDR~wJBNA+DpyozPqP}x;xcX~O$1GhS{P%Der9%hW(vPLrL9S=PMdM)M6tz^PF@}G zrL{vq6?d5+dLF3;r~we^k=f}1LU&VInrMSjS|q%s7Y#8qfnLxaUKa?& zlmDi&D#v-zhD4JDf^0uSf;^G_YnZpCrs6n8!oI3+H&utBk#BagD{0RiNv%z4U(BJ> z6&n3hKvY!YF|Ed9N?Ja8@3|v6Uu(O$@h#K{4PdI;@$xge=sdO&14>#vQgii5fD0Wa>hPiohT-dWJwFFDu;JQpk5%1K_ob4$O^(Awb?-;rZbbwBqA~3e zxbip4acfyXHBGjox@=dBX^n9pmw*3-jQSj|(9X5YE2R9-B&}=lm@un7aRh$e{<$__ zr=fw^YP5y6jH$hecdd;4ocXi`31%p{lG&#<{$joXukk%GrriXeHjwfcY0Rxlm=nq} zmw&~4thmy{RB0s~XJs$?9OjT8>M3`9!7|)heFvLqa|x3%>tIp8=^@XoW7z!4>R%!- zZ~jgW{*n!BrXZ&OJFXI(!0#e{oslP)6PWAa`3HU!_kX6rvj6y!wPME6=9dn2!R!vZ zwF(Bvp!Mtq){gQUSYO^}w~XI_085CB+sFp+3A?k`Z-jHo)4R!Mn^+V}mmR)gDMP(+ z4Dw?ZGkl9*Hh!MS6U=7^Gd#!hFZ>?hR|R>3Iq;%ix1G$;48L&v9wSe%KXK8D=nvp| z62B|>{h3|kTQB9TM_k*%9UtdFt4uVYiC#8#wsv==SLav9YWaOXix9#Y2UGn z%>DcC>GV^<)uF8K<>2jX126x*blJg%@s0cByE|BSkJXwxc7aHG?~~u}V2AmiY@ zoRgXM%7Z)E5*8x|WV2ZRPicE*b7`E6ht({n?}Sh_Q|{Hxgd}xDmnXS{?0zWm$l;X@7WKC7yni+yW0=g zps|GP^FOik)v5k3x%`6~_-Ymn0c= zkfnHx)KsGv?2a8~hPT({Fl#DJ7K92i4zrFPi{UXM z&|99~>zFA|A7-7w;dKPIoE^r0zhu&6HhN~G68@H~n#-yK7j4>A#>x#fNq+%>Z zkyNM;`pDru2Yw>iDRL8F?>7*I`kz_d7kCj#vihg-q$OuEEO9iJwj&yRUtkWNbbE|e zQMyo~EjJbdY90ke8qM${0?g_$`bya{U{pKy(Xiu(m9#@{rtlZ9RXiEna$U&c`b!%B zOCi*AJE7;-tNDQyiFrB>A5nHs?Q4BSyORbpbmnKlr*; z&yx+0vHEPN>~)MSV5hUM9%EI@)l0)UDWc>VUy#6E6VYkjjvQ-OZSViKrn5=1>KQ~Z z-DSr!%$GHh`0P`6e&oLV>I`cdvi5#SKiZHcKercpBW8INLN(o?U_|#y+LbDu&axe0 zNj91U)zxmE>Vo}YI1asMHsuz1t`Lg#z52K&KF3UGM;bz82#fZfHCJJk0$03<2?Je7Uv0?w8^QvNBa zae{=csfGB6-$fSS(MHGgrO{tk;oOy{=cPmzoTyY7OVu>7lnRREY95!dHTp$1y8<)vtNiW?+lUpgyQit%5&6zl*4Ymtn$^1| zwa>q9iqqSk-Bt4oB)a<`5F23MEcah!^@zcT82-7+x?)6xUSo6loc^k~6sQp8y4{2Mj^ZDsx6SP1JU`~SvPvR?AhZ}9x%&P%`RESOc3-LA9R z?16muI=h1MJO2(-=Pna|XRGmW`-3&+)&sKjA8d2bf-~fj(FS6Gy*3Vd5j0jXB|b-7 znW8+l9_YUe>2?DqCqy>A!FKs&|3(7hPU#)IcCM&x&FWN7y3$5$jjeL_-`KtT++?0S zaFJYmi}_2_P1bb6=r@VKm`Bxhb&Jx1RNaE{(vJ6-?l7n*TjIU)*UC*s=NHA5~{z(Pt`dU zRaf!N>g;pM>Oxa{+MC7Zl%kuVSSQFuf3tE%W>S-}qTs?KjKcQ|Xh1ZIuJb1Muu|N0 z59wp!vZ8DJElqW0##!?@(s7GbuX#w5S8H;2d;!3eW(jsod7qT=jcoB3^Ri@=6`tDq zUQw}E!SGtY?|F@!R2xjC^)9LBLXzH*9p6;djMvziVzGHoDXMPbo7I_Lqo?W;sJa_k zi?wDYpt|ocw@%rIy{WZ|r3%2St9?BYrz1sssn`OhS;7pKsqYc%$8T!z=kzxSkMzwJOBKoyQnlnJaX|R_^x#yp|O-3;6<9!XrVoFD}x!M=1k! zGEFlM@BK(0r73H>R-~2Hh@n6mNUh)Ox5=+jQiB$D)hiwSX2D(L?=%#(IeJ-Zuhz4} zp)V5i@S7@d{vQ?KbWLkjp~hCGbIzx}COH+G_*$_pFwftnl6kJfzn(`Ev93JyH>>3B z_8KARVp3)P-^|bZ%fvUdR3%l`Dqt-wes8Mf*z6K9N{_~~FgW@U&ey8yRD1$KVlLB| zx*@e-c;tH6UW8+c*fshAIdz&pYt9WGKcd-zFpIhYp^1Pii zyYWDH(v#ePGh5_-H{O)j2F{I-;eq4jpz?eiS7ymW<#|J1dlvBkK28p*z+3SLP}t30 zMi~C9q&z85a-ZQkGJ-tzPKcUXd%I(#&_oHLBkkchiGH%pU=Y7QuO`=5;gy}St@=am ztHM9(8jTP&uJvG#cSNyG!$%C6v2r=1r^(Y;xre9GGb+GXxoZFgE@5ivgMd|0j$+Nu z0pRf5Blt@n6<2WEkvFic4s*kLV|yZKRSLfjGY>TtOGtw~Gd9-z+n@p&RLGff2?dqa-xuHp@fIiS@zX2FY zS58M6fU=(|qNANHaGog5z85fhD-2&c%t@+)x9mI>Yqta)LN9Rj98i>2C=(CYAA4oY zSlr!284`O?1EOAwsI?B2n2L-Kd3C_oRR)+7>%I+SYjrAR&r1Tsho@Xbsl!o@VP5AMKX?6x==P zf|qcxoLIYuSi6Kp&$CSF5N(|jdALh7Xggv5p*Xx7eT#bMP3eVBj}DtgosO@TcNu_U z;_*wsFA+S`W34M3)M+GjtzxOYqHO&FVr)GaZs@y}71{^itK1B7^+>6L6L4|DY@OtW zALN|m6Kh@I2y;ab9Sql1n7RY|W{T`!Iwcn05Gj7k?bT@&C5obYP&=db5N^xRlI7pCXB z>$ylh=b`85&25xYUC;H>a|11Uc7UGUOWLr`j@NU2bzFj;bLhB4J$F>cP1kdu>9`a< z7op?k>ABx@TqbgpyF!4wdVaZ%wT#uXYxHc902}mNYaO>$&-K@HyC|1|GolJKi_{7x zHN{f{9fi%xHCgqX8tVpxPZ@-kQ)6*!HYK1KVbNH$tQw2!Bq_ng7!9H2)Yt$ZLdqbt zoEjSpL|7SwmQ!OxfQT%E&~j>Q7!XPc!UBP{tQs2$Os^6Q5L!-+Re%^!2BGED*j_-y zmqBPbH5PU!C7}#L%c-%jK`Du)5f(kG#=>l+OfQYmb82iN5GiF4T276f4#d1N2rZ}1 zPr<|mF0%|y%c-gJfFoPtismf`0p3kc%`635LriMw@=~A;I%rKP&{iF^p%iGByPV|9 zYgm9m0hf~DRhxX^e}C#t*W=E81E@94llap1`VbLOASP?`#>ap`@tsaVC{P5vqQEBA zdzD6UeUnxOp+FH_hT>z5;)hKJ3splnkc5;WN!3VJ=!Fmp6k%m35;cksbqYd(BC-s{ zFpXk>PC+P8C}k)tLo|{$Itk%G(yI)~AdRA`PC+P83@Ag5B?T883;Mln&RAQUKey`rFzo2OCy zr&ACrWroGgkQ5EVvJ&frK|0}U66*pV)rxY`DM;Xy8Rhko%8ISi{fe1~w*L>Y+u6K- z)QZ}zlaSmgGw|X3x^GCoMWc%MEDQGV~w+ed!6 z5r><&Z@vQ1X!sO~QIB(YQUxuFoo}U%!okBmJfqap4~?Gbfn-FYu(spuAR$^kCCvf6 zo39-{z=f!k>ujDmFgSW%H14md$70mO_SW*-0N$jWzJSX;cbTu{sWST?9O|H8mzk5{ z7KhT?gpO!@YN=N=?ib+QQ`|s)iccn6==MXrqOM$|iLqlf9%l7>tb=%byB?2}nPUt| zJ#mKuFDe@=$NYxh-6$LfQd81%DMXLglYX;Tt3jso5WenkP;s)v+*QJ3o=h!j;$Wxh0n` zc7fru(xHuY=z2QjB|eFdMJ}Ry6Nv?IH6JIH3skJhs|$YD@P}iz#BcwMipoxbjZJDn z>|Ux(O8>gt+j2POM@WY;5tEHlwrHgsjyb$-{3>EOm16NQB>AFKD5QxmU{{X8eUX?` zAjSC@Dh$nuR<9$`N4-af1rto_Z#d(4ciL+wGul}bGz~9t6kb)@88Z?67Yv8ff&c*6 z1F+2{{~9lA8mKfncj-j^=Qu>$4paD}*Yr2}Thtq)-dAjMX{!=zbG{dPRJ{~t)Q`CE zzk;A<;_3!AFVoh*QSPB`e?rb6q%@{~gSNzk-W-khcZ$9i9H;hki&GDn)LAeBRdIO< zb>}{FqK_lvl8F(!p#7%CIm*v=lT!{pH?`js4yUEdX~mI)l*!m7hdv?_zJKyBv9?y) zj#OH0LOC|R&;A1VgzI)idWHAk%9&mhI6|3`o zQ`%uS6Lwn040;VYS{)VGr{wJ83k=aH^#H;Z4hmPSOGVi@E$c~knbj%51(U!Lz9!u(g-D*k6IEjVJ-^EiJ zn{aP=CyBdt!#!LaqBL1UM`PL{Ew1!pgKPi#A2|E?m`etO5{o7?P6KhQMVmu94SZlD zy+FJ9pW!`~pZ%Giyc@_{)N0~S`+4KMzR(-JW)T)0wobE2#`L+eLlCcD9!*m3W#oJ? zSdI_k9qJ*gJh|FgUGPwAA=>fHF>0ZDC?6plgPH|P_;V2VZuMwoNu=O+q%$EY9SWug zLVN?x1y}STz1*YIO|%QI5uaTtee3h6hOm&Z%fR8ja(R2B_6|qc>U6cGg;kIX>hpSX zD?YW)F3a2Xxg8%+lD{iZDt-B9S(g8@mTk!TP0^llYxFqNB+~h~4M`UtS zt-+`4Rna8{0ZJDPNqqkXo7$tv71b`-DlRyz?Hkpz_A?t0wg0@^LqLkOoapiuyV23^&4FG)Wp+gw)w6`M0&rMQ&R(NIQ) zikkiWPoMBFszPb&$MtyA1wjHi7QX1 z6}7jUwql1KC1t}BeH@rVgjib=mBZe=4wrK%7v+W zg0->0iEgb~=h9b<)wyo?TZUept9=Fe4f043n$@4vexNE1Q{OS$@V`W%yL(Y;)W0a9 zGF68~k>MuMllw*0n5yxy!HP5Xhu zVW>`-eb^HV0eKT@x03o4C)d*TA$I4Zb}LhxqP>MtwmOiZx?H@{i0Y^UbNG?T8;fsj z(qh_f0!9ZGQ_XdpeSqe=y!9`F`@gm4fmI+#TA`mYl{_J`i4Chr?{MD01BTvYjl8F* z=`b|^*WR~=MOC$buUUJ*5kXKvK}1JI#bXF)c&b4_2Ngv`#REDDD4s_}#Z!ZVC5{x9 zxvZ=|Pp8Ms3e7xq8uNsuMP_BCNoCJ7sQFM?QJK8Id+j~L2K(^-ulK|I<(ccc_wQc! zy4PW^(_VYsYp)S0L->TYP<4JC-$`~R?{1L8y5q6Yw`$yIm!e=P&Yw#1XLwQ#NJ~$i76AhQdQ$zW^rbp4voeyJR|8gi#;S*Mh zZo~NVhNr~)!}wl4Fj^Gc$A=gO;oCI+Bfk87@qWGz4}-22M0c+kZ{Y*znXuWypC;^) zz+VzUBY3zYEfwdWI%@)hxc2uqqp)_2FNuB%3>t36x41aUVNT%kFHCb%0w4I$dfG)D z4TBP%_O)Z^7<9~cu|coC<_KnSPQM|ga?mNlaYW3y$%SWR;B%FMML6a}PDadle*Hj0 zkX1Q@qB|GwgE7N83}tIs<%`vC1&4CLAr>UcjT|{@fDq|C2z@5!dkkCR#2^Y z$kCu-9Te}d29Ct!0{fQLg<;fQZPB;>G`>BKuG8CEGR>5PHBdY<@aU6Eqlsp$U`F8& z7^C5~U=?)p=%FPO@L!PlB0mYU<-{a)8FWJ-PFG1x!zAx?Y`rCZy&3ZuOrR4p5!434 zK(^NIC|O%j@+LGfl)OoKN-60O>HN()XsvnWJ>H#FkmFPmJmrvw58MemXo85TNZ_V= z3W)jgkmcrOmvMLMbLC2WmNusEQt#6{Exv>DE_0TeP%)(mhLTMtT7gM*8Y2@*HWwnU zG0sx;G4lpJd@ybO1w!wvcz`}bWUuIb8UukM`hIhe>HE835cL^g+yyA$OMJqp(df)zaWPYwzFittQQqG5tK{Zm|?PYMxS%OKXXd zW*^#TSiNyG*cmkvbJ|Ff;*s)!`@v#rpY{3e(N^SNFSWvxUN(`GlA)0}@#H#oO5+9L znL;Y-p}nNY=Wrd`u;)}RtOhQy;A4HPg)lD89KBlttGul{2M9~1D<`iAN4a`DFq-o=n7 zB1ZBalo#1dSF}iV_K7^5++?R$XOT0KzlLant=tk|Ue^$fznEp^J%SKkXFR^SR_wI$ zDbW83o-xzbHt3H8Uq;2?9DxpkmlJvgNu#2uYiKQl#po11M++YN)S8Ci4}rfccxIE} zYu1P{DLhI%{~eYZXdxlVIlF_kbc6OLT8(d}6P%ah!#r~--MeV~YQ#Uvx%b~Rl^Wxm zh?h=$<(nEbsxy2=wI=VL)*&Biy$hTJ(+D&x_2m;G@rHAfA{t%l zk4TM`)*+So@%ScUS?sF*WWh}>U5c+9PAw0G!h5N`E1`dm8oaf1yvaRjJ~{%ux1Dpl zyEQ8D)dd*74~~_uib3?M=#%37;d)D}Gi$MYQyhWjmxltM@i%XZuqBUio=lLZ!|UD@ zQ^^46sUdnvwEp%LUIqW{nYQo3OQLw^x}nRV-lKSq!7xIU;h=`_TzY%M1kqeM_n9HE z{^5aOEyaqE`-@z0Wi$^NL`FH9o6_C?Gph3Gqm zkBFjZg{GPr}Bs(dbesMKCc*g&-X3W74!bgj-Al>wJ=7MLg>fOP zlA62v644*Yl%+U}O$42s^|Dt<$E6;Yc zueH0()a|Zv>XO2Dqj*}>Pc7|( z{_=*paNrww5NmQH@PNNmOoqsdlqIYpU|w+9PUXBZPdaMhpzzmm3IRlPN^lQEU3@-p zQw3GMBiSPRPmOF;jdIw%J;jqqJEA;0AxBq}=p%PH9c|-mq+N%VWSzED+kSVXA2+DU zHsC-bfbLB6oe7v%p^BiUV|do-T>!$SQR46_`J+l&zK4g8SfpXh74Jg5`jwtCTXz_s)j+ z9iDyIpW@WiMj6-s_!A$YRXZOoL<^*9xd$r(xYNkA0iBiiy2R#d)m-@q3KI4v}F z$oI>N)ymi-i|u~7r|(|b$v$#Vma(Xt`mpqD!9omeO?A)25U!h;xfW4A@GXd_#+LxX zmccvve>ej&d6aF=FtH^Ae`?sxBxX(KZ45RMFcI6mriqw|d|1WojzHjO{7p~PNPWX44JBpxK5&f?AZ9$z)9-;2$Ycobg0_f6tGc#fh(wCl?uBrLr zC)d@+T03+qUQM(f{Hg8#rWpPH{`T3o~bCa!lr_hc+i zjSDLqV&+sH5mt_`>AjJ4^+r~r=HGlG=AX788OCV| znU_v0u~OHx1#xdGc_Mli5AKlIL$MI7?zn!&?)f~L1l)iZnb7OQ$4Q|P5cmn{4BxG8_8 zT3(mcM6s7tCUVx>HvF`}-_vVI8#9sJ5G_#J z-vsL84K!R0#3NdW@ir93KJA`whz&Lr#>J04rS|n7GWLigct2^B&*HCEYxg+zwyYs@ ziBxGk_?CJjTKk98;*ues+C)q@FHV@%BX<}qH@6)QMjUIZ=QZtP>cx_uPinF;j zEdfT6ROgRL&TX{V>8wp~7MPN{o=D7>p^ z-KNtE$R@c9*R#@g3`-MoMZseazjuzK!L}t={!Yo2Kb&Fbf6R(M-cs%2Du>mhTDkIv zPus1fadHU}hmW= zH41k^D$N2vpX*sR{K!Q4mEV@)mS~~M+VDb=K8>2yNA9CG8c=0Hq(;$kURb6`kjsIA zbiNl}gNpEv0$JAjYG~Joe1I}gCCA0qIcPmU_YyD9k*h_m=kj~8Xf$drPX|0bmrv)h zZ;L;GX3Yee-w(6i4S_GLj$`k}FAU$>aC&3sK_zJZ^{Q zka>JG;Guak&M)WjEdI+;F=#&G^ttSbb1DwL!%K*}>pNn>eBJ^2o981=qj+gP4-ZYk z!slt&Um3kWvg^+tZq_3A#PySB#f|wG(C^C><^}vQzHPF2V*%{FkBt=nSb{lB)?{H= z$j6D=`Me+hdJ-uGi~NPWjGHG3{4aGM9Lzj@F^>>wi+CWvJWO#V2;&jc*&SdQM9x&s1Sw z$~W_cKQ#=&DYb*cri~*6J3`hWP(NYY>}phbS>wz__T4NYd&llk>kYF ze7=6K#q zN>s@YV^povW1v<0i@|*8iDWA)~;eU84400Ft@gqJ+*FCU1(!+sz zMK`cX<=ElWsf^7T3I5 zRHIY(dlwF?{}s`0`6Ay~e13($dmtV;TRw2#1MsBVP?|-N`b9X?=T*q)i zr@Wtl*zE%Wr3E_=CagG!=7d@7{wMG0$d+pXSX`J5raokhbXFd1Ze%W*73?pMCK(px z@wLT`_#=4nV(wOm4jFGomNj;+CsJvHyu0_nMV6>|6w)7bGg$G&-UXKl?k(hY`g})F z;*)_)k*31}MEWNqA zBH7bE+n`Rxf8As`XpoVkS=w-4ZUy)p zq`0o2&v+QR#l5_5^I^~_!vHiyT-wV!`y(Z534QP6vm#tHe}#8wbozaBT|#}`$aPx}N@aV3GYAzn_2CMm+x-k2ZWKK79>C^UOA)?ls;iX+|5h@GSKq)4*aN^~dOCDzz%^ zcjebCyCSQoUN@X@0r2-*XKQ}`2nU|ZQ86m^Onu0$)?#V}pJ-?;Dk}I0#{slEYYFak zrpf)P%Db&-TnK>Kq8Wb_c7ysChK?KGK=aL*XRq{qqBpo9$5-TAi*iHhj`01>O`7~V zlVLtg4yq4v!{u~Y`xAdv<#AAi>b^woWHW*VS&xYo`}jQ$idk9|f2+cHluk~JkXgqM zGYez52Xu%{X!95hCn50JvlTch6)kE5WH`C%MwELp&L6TCnIhfTwnYq%uE&AcXJcK1 zeEJ}^!0oQ%&~JW=^h!|PcC9+lDZK1sGkkvnlvEU)F#cdF#o zcvdi z;&-XMjrcO+)hevXp@J{nQbF=e9q*qe<@8LcF=Lw(bYz?dvXNnjn&W5+bV8TNPV&@# z2p|)?I#WhuA>9J_LoWG+I^L$^GjzOF#}C!<-J^AmNF5)l?d{^~ zVct#h|5+jek6>n+vq@&mOc~1rugkcU8Fl`3#s4e+G>Y^2UEZpb1+~4wO*P`EDQ*y0 zD1c6(g4{XqM``UQK2y`BOhP6j)cj?;i*M{-OJO3_@O8w8Hugst2dfF*k7r5gmTFR{ z!OOv6k6q4KcG%}>}=z#Gxaj)0QFp!ZxWcC_1omL-I_l9G%*{LQ#Q}aYm zH(*2hC?Zb+TARpka7R&sI``%#?mTiQHR#Jyi2EBi5_6Gm6#OiB+F!#VVX=y*?aOg{2h?`P^KcL#Uy9QU*FJO{SmYbA3q0NBnQsebRHAO-s0x22b<#| z;J%1uHS1}gSKvuMuzSGbVSzU|r`YxuZyWeZ4dhsd8IKtE)i7~!n4xz>q70pj(D)<< zp=Lsfe)JkRQ`~urhXr=ih3lz>>-dR@QvIdI6Yg_&L%7e~qW&!&+WvdUJPFdLNwgET z_s72o4j!dT^vGu{WkA%sBEiZH#`=k*c>M|(_D|S5gHa~_^5_^HN5zU zs`rkDyES}N!vYO+G)&VlPD8VX{uaQhH89hrgtTKl7!33MG8LwyF2KKoWv=;%}#4&gbrq^L zHm>2Vhtwjxs^JL@pVe@qhEp|6(lA=X_8Q)KP>tt?Lt`#!cu>RVHGEjZ2Q-|op;g0B z4Wl%yD$?p$bAPr;b)V31mxh})bmVKyBn_iA4A$^=u^NF}!?!ftqv2K!S88a}aIA*$ z8g|z(Si{?DMiq9oNUV8}cj|nMTMVd+p!XW1rzuzui=*%Hds`e*z2gsai`aILGN5^) zBExNd{m|g!{MXrzv}9Efy~`jysx++D&|a>|vsJ9n+|`;JN5IN(_7^pLNyVVoR4hND zV)aoKEu|{r-xevHgSp;T1+^O5N2(c0+o;N`G%PPt-4$BGE)9b=sd9^kHVuOwRONOJ zt2J~vHThOTG-ywb(zKkFKcXtIG8L<}5-QXZv}?HQUA1igpO8A#|2Bf?5o!q)=BOF` zzYSldg>xNO!`V(4EDmZ!_LJHjYY_%%Xg{UO&6>Mhb6ZZUa+ij-O4XfqMnzAFMr+}0 z9=XS@;o)S(AsY|Q5>guxSFysQ=&QP2n!8FvlXfR&lj>is$!j$%)8s5y%}|hr-RxM< znzuN2)-uM1ugJ++%?|bIsZ8>*nA6h7Wh5tNBqymI$effsDJ3y^X5u(&a(eRE3{SW6 z$S00XOh~k<+B5AX(c*AF#VSnqC>Ubq(vq3plh2_Mnqk_i|@1YD!LaY*g zl}-EtAisscm*97)!SB%8dz5Vk*vSL>D~W*d{gqgQOKj?|OaQ>uPSo~Sf($!_Ax4=7 z$cj-WN4WPWtRP8YyFpEVZt-yp;>Z*OVwJ8T_7ROWu=yOv0sS~YX(I|_m7r#Ihyi28 zw$5QYVijXR8oWKf0+A4_v_qc0h*df@qli$kA}CskXpy;BVO1j)hCZYU3SLHrk`;y; zl!DH+5R@Yb8nq`rF9so`%tO0v(MA!CZ1@Brtedh$q8sKzT-- zX!Kg14e?^Y0Hv#_h8K5_6!Qlt-FX$TztX--8T`pQ@~Y*$(x+ zS2<(|$m8+>hEF-~DoM{se0xS#9LTf>y~hA8-0#=|ECmu!$<%QW0! zzihg!q)Q21cD*NN-LE_!25tXzXouip1{qsckoWQTL`RDyYQR&u+ z65Iv7_kxh%3t&!z{QM|#dyJ)*crH;%X-!JTNeUZS%z4(r*Bg~l0RsQkmwytpvcK;Dd^o{eSBHCp*i=h zHrkbFjz%qJBrEO1>@LRs4a(HQc->-KveKq!(;Kcj35(Y$#>zEyuUni;R@zMss$?wu z42FO5_CvYlo0v~VGbuAej?IIpAKVh;q}L$BWKb7Y&20epb$N4p-w5Q^`~eKyp!iJf z4n1zMbcE8$LCs?~y!NAtqV|C~4C1m4*^FUE-rt1Y9bsfG41XDn)!a^ZS3%X;&dA#3 z{An=7abEoyV)nmQboXW5PXw@b8Ntki5!H?z1!qC}_{bf86Y*&A>D)0gfx7}B-(|H}2?BZY z?RAS*DM~v>H0&lNAoDaek9xP-27dOo0ezRYVV}=wP#T2`!ihXNYL6z_tzS_eT6|62 z`fy<#eZ)Uglz_h8?jsx6?`U9k26G)uN}viYBClI~lcJb=V0;Xoj&U;rmwQ1bS*Nvf zlub}a*)ljp)F`EoqudAozW^Eo#m>P-7JSu+{^loT@xBI@Npe&W>FC{!!pY$WjT7Nm zTyxggkA|PdvaoJ`tZhac);6xSnYDeib!|{}OP9aBg^ikI9TFUc1m)n2Q|W&mrF0ub z9?@9}JKqZ)gTTxJ`TJXX8JKM_U61i)4Cf^sxQ7U0lq(ixg&ke-9*i3B`F$F zT4rFnl!{9lXd%dG3c`KzOk&%$c469Sah>F>ZL7k%lOk&jT2pxs{1FCdGoHItppD#G zM`BS1HXh{BY2=nVzRU&xD>|J^jPXk*D^27so_XdF$Q8g6mbxP7L!cvvqVP*aB zFNdH$Gu6C$-6AVh32)xu+yG~oE84(nKpt(cTWXK@IuV&6fF?zLEFcEYQM+%N91e1t zv#MAFYZhlKJNsd|4IFLcaovo2_NJk(q=}A!Bi`TD)*~(Fqzy?2SP59ItfhTZq3<+YO4#rh7v>x!R01mZ1T7bi@h->0g#+ zV2444G6>oYg0OsKt&tp?Iy`Q162S&o($SqjRWcZ3jon&}pp~)=Q-hxfOIPj*E1YFu z&wxB_#_JZd(v_~cG{Q%tj@7zv!GiLzECX7XL-&Nb*SW(wV&ay8iCdhUxXIaMye@1N zbjQuZ4QgS%Zc&r2^av}5*QcOcnzz?2dQMQnhglXF*i=wlE>hNNo!l>ghLQ{^HFbN# zhz%2zPGME}qu4v3t(v;mEsl_P*&+iw2s)v8d)?y42}*}x^o|a5&^x-}(g(!-EZL%S zhSJGIg+wkV#v za-&SjE!%;=LIM?#zw9i5(mhHb{~lRJOGfUwpy#!Cnz|_tZy0KX`9aJZxA7|gWruiigY`%1SBvJ5RA@^5fccADMWI3Oja ziztky+31{pF~0UPl6^2_Qm@7haiYHCeg8KUP24;~>jC z^QT8*)G+(=&TSn=QcoTmV<&j7d8;*Jc%x(~-rO>iP$CKLQ)08Oc(HGzm zbs3i%AT1t+6fRCv;wG8@WngDOx8X^Jr+2ps^<$xiR;*QRV0A!M3s-Zy$<{2*H<~IV zb1`C_g-brj*Dq}~iYJEhxItOD<6SX(y3#L;Mwp$5(_k_(Qw&}jZ9KYjD**Ej%saXDHp;p+NH?&!csj^+lZjiPXd5*lXbm|260;X%3by2ZX3m|0pBoHh?Sta*Fg;+Gjpk93loTY+-mZ_oj?p9%bEG(`i3yTS>%R0uzr& zM|mt~e}bamDd)>M?J*>WvPN=k%E<2JECQsC_()#o4(r*1wTm;ec80cpo8!ZX|5?iM zF))=fCuzt@^EBT#`mkr|Gd2I&N(V=)4*sk|P8-%CqcsX3h;?{0w6<+^a8+wpkQ_gQ z^66%9=?qeDx-<7(udsba{v+<%5Mp8>`7KyTh93*T`(;Rat7`QjZenTUIr|>ehk_$3 zdbgTxpg28SX-k9QW=dxpE<0s97-@b)_Q>Zj`5eQg(&N)PTQRqV&kgdSIm$0!eAlr8 z-begry3)}BKl2LsQDyZ6V?2kyia=hufpNPw!^28jbS7tWLD5i=v(~$0=&d@Pum}YU zPK%il(?lAk(y%VCu8l2X#*C$`a0+KngB*5>kX9V7E@Y;hWm0(GRCGp}5WCCm2}t2u zVHbagxOS|=`MVqPE%-;PQ-f70Wq$7nBM0&h#FG$DR*n)Fk@= zltXfApcwziotMv90m%@b&fQT88U=!aH*)bx4(4N2id7KH6^|1UC@k#OU%^>A=zjk7&|^*X!n&dr8alD&wau!0>_(fqE~>>%E5lbKn0Xav4}qdrA+IDm(Q&dAyba+P z5+Wm{pm#S4L~plDadnkGK7x6Ebe}70hZH z%Miw+BeLe8JoKve^_)ElQe_yy_3qwA)*BNfAByq;Bm>fiZ7f4FdL3QZ3I}KBL0VW? zfe~S2A?i%8qzhbK$Qj?@4J^YpmSF~{)A_sUS@3G@!4Uz*SNt(Y38x8=1ukiCND*D; zDqTrr_lQ=D^tsCLzU2>LS!Xlm3Xsdrd#fdDEW_H4M@Jk(EXkIw81qZ9rX+(f*4T~8 zy%mJY4QwJu#pz|DXC9)eewedYAHfi?Mr}8Z-H7S}76wiPv&M3YN+%QB5LJKscFw*9 z9hOm1E-**WX~7!HQU4x2@qM1MWLWe+IU5g>Z?i_+SU!{PsgT*%s<|S6z1tf`Y@0_f ziMu)b4s=*k_qxTIc}ncCioKkD2GXZMZZ{}&oti>Zw>Jzv9#q1+7|^AfQ}^h?*t4ia za({Gyvng-j0a!^W*34Hr4s0%G?#(fCH?hF<7IxA_VX@M~=mSU49-vEj3Utxy7E>1} z{ZL?d_HJIFBq;^!74e@KC8X;`JfGMDjjg8Ss(@VcgQe8q77+`T9;Cap}b&8dc6;fbbX0AcTkQqxuVCMg@!s?*s)`jf{Svh3UI=!)wxgj&_ zWQ!rY__2YbWd6Io@W0y&|GT}A{dareq)qC;^#5Ud;h|p3lwxDp5+!Bvy!?5y7S3Cf zJ0X4Ym?hZ@*c(0>%T|lqE0s{r4vBA8V)xMDLm{h_|G__Avzdtn1sQqEmaIxH$j-Ir z&s(xs>@QFT9=cPYTs0iJxkl+?Xo3Gy$X&K*-r`yLxgv0#QWJ8)n4Z5dah5%Q#j@PQ zC5vg#3;Rk0tXIN9z9p|o^OohWn6+@?;#Kn&=P>q;7_wdo_gU{VAva$Pg;vi_d}MBZ z;)-Rs@<&)t_#Uo-)@iapAELKvMC*{swF?Vk6vb1Hn%MpqdQWU96 za#k$Nwa!|cvoLou9_Zp5#4hsJD{YJ^IV@7NdO!&Y|A{mwtX`g<9Ik1Uo!%@Iid;2wuOXg0@;*I*Q2&);?J3A77*8t^Q(7VHJD-%>zZ4YEKc z*zpNzD?tbF-Yo^tr>zFBfcijAn0O6SYVi6!1N!|0*jM0S>DL)6fD++sY!=uGo^SzZ z7kK^t0Nv&Rxv5|oHWpMuhj3#pN)J4t6LbT-ci#XqNBapPend4vP8jtw+R!x2(e%3q zXjj48pgu6*6HfdEcK}|$13hGVp}K*a%P#-n$6^JZ%n`{|7P+ zp722jF4b_90iS{;zZSgSO0T!>la;@&nSm{YA)fFrP%(HyqshRwgD30Zfn5M!1-y-c(Ue8s4Zt{`3nIe>{a@6aP}p7IVFw0x!+JM(Gq8VmBn}-5a1sc+ z1ep!^7Kp-D1LJ$ByagyUz8vVWt`lAZ6(B6(?H&dP+X{!?oK9x;HK1LP6Yd99fY+PT z$;|H86L$tVVF%C!@Otw)nc1HNU4@+RJg5%5-nw4jbF_i=!Y&09%-e)RK^?%;&V^kd zy0da%T5lBb7_?;IggyqAKOT1vY}QxhgMd!a`3bzSZ|SE7^V;GO9hvMOk46E3C;SI! zI(Wj@K?}j_t?^{EKN(|SWsnno3_1Xw@H@~6@U_59Sm!B=HXvE%{m0-#484h-O!vn? zbqGNC5y;=BNc;?Z2k?Z=2dHwwKoH4;faZHq)8Gl$g7Q-F+5ubz+dZ`guMHnMWb@xY z2>Z6D!?Ax5HY$Mf!4tj<+6vwU+%pt~3%&w)5@!2q@H%t7G~>ruux(+M!U!`!7VtLU zrbJW*_%h(W5oq(^UBJK;HA6uTFdm~lp~qNH`0gl}iV%SCB*+BAHsJ@LQ1E(#{1wPj z(K;-U6OILCfG3;?$^ox8rhAO;4zj|NHGX6&?h-uVbWjC&!i^voc(1`6yx!7I7Wa5q z#&1DRmopiuB$%Q<+mvUg2`^$|SK!Pdbs9S*`GjVCMt*&+AZ&%u+u{W$(4 zqYOOZ`=H(639CRZ@Pwaf@@n9KbW}|``Uuctcqfd^z*d25ha#C?aMU3%VKm4D!#3f9 z$xsAu2M(R8@)qFR_#4rokXHk+XVJ9h~(y6WGqkR^~QWM^1lq)j(7+wLA$|wjrQQln7+o4_D3Cv<@pf+su$S_j^1 zxCc)L{nd+*IC#QMi%|au;P9I7!IN44fyEdg!4p0Tx&gi%`0x^p!lVz}u^e_>tO}O{ zudPw5rWW|udUQF+*#p=gjP6az*t;3F7z8FUtMd_qQodr+W>fy(nR{^Nrwb_!Gh4}2`eW|gDv!FzWGkQ}mr zf1vKc6RrmZVT%CacN$N4-?OS5A5*afFQUGoOKKEiru?t}T@;+LdqwQ~^2RpP&=q z2{*gYNGUAPv;BZD?l|h-v;a0_Fh@a=;PFutn{)zWI(U58#PUvREgv}V6dEJs_m4HQUKtZPf=vx3xTnpVaf>J0xbC)^$NZWIHwv3E<)V{CwzxU!P|i0|H7St z*Ka7GjRw2^jfS~ck@yz)DDW=eGmh&hYB3E_6An{2mW$!=TJOP= zRX-J``xD>^r+{vN*PHLjv|rT>iNVfJ7-oWz7CgRVV@{9-yw@}jo=o;{w}F`tJmD9h z=fPLEaWok0$#6fY9kzACgD?r?2A>9ugw?(dyxw9@mV8S`&de~<5+;Bw;M0IVf@s3Y zI&oIi6=oL5%Ygep@=@M{v#Y(pJD^kxCZ{iFTcKnJp6`!u2f$YY$*O(>yxzJ_*7u(W zayAr3al+p~8Q}HSb+Wn#$8)w2a>7oaLhxoFABkNw;DdmU|FL4b0-jpsz*on>YDper zIU74334_<$yvY_mHXU~fb2VWOC2zU}y1-=TnX_Cs90i!ap zJ0qXQe=r^+HsP6FlKkkPW=v)=b7~k6oIu9sVP97jy_?KnK7RW`ItB zw*d=g<0dH{;Co9^|Dh|9yQTR2VmSg}-1eGyA=jIKb+%z?Gk!52#Rwh3H$cyWC%gbU z0G{wR=mdDZ4VY}hpR7dPL;i_FGBD<@LOTHOw+a~oPuL1Xa=i^#Z{H<5uW2<(1v-R5 zpnULzeL%(F36ntE!4r<%8E-b;$(0uMioBobV)Q7kI)8pbGGMODZ~);)=V2yKEr#aZ|NLEncw8W{5&>fZu~{pRd=n$@djWY{)!mtXo3Gim%O%S~w)&iCNXuOaI0sUUrdI~TB zRN#O|5|}~|Js36vU)T5pz#l;L9#{(;bU@V^3Oudxl|b7Ys4~PuSPY_g2w&0o3g9)3 zzX4PZs&N{Dj(A)s0Ace(Xa|VMAGjX07knXb;9*S%Xa!M*2xn=04zT(N%*D_r{0T%l z!ACiZ1JTROP~hb^5f5~314q0K`}lf{|7l>J1yO(lz`%FZM`sZ5El?2b+10>5L8KG< zF2-{ZJzfcE*9!5p6=ws8bc%sjKz%4IaON>&1iT%143q}G7WmUK2U;o|IR1gP1x10U z?``TpcC5Y;c0Hx?WbY?C{w~}B;S3PHIoW{kgDBxD;J`B~Zvnoj@fEzN&ob6S{McYma+R=*!lZ3tp~xx%TC#y_tI{!2bbdM=4nV diff --git a/bin/VulkanSample_Release_vs2019.exe b/bin/VulkanSample_Release_vs2019.exe index fa83c3adb50431afa1e648d66afc4e88fd6d8e04..39f91a5380b943e414bf34302ca2953c9c2c48e6 100644 GIT binary patch literal 375296 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
    (3Cy2l$2Oy;EZhE)Z2SM{_`dDu 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�oM73q@xJiPB%Q<#}}u)pXd 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 x93;v2GHpsX^V~^r`GZ#ZoPaG-qve+K8d~j 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 a{*Na6&n^8 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 diff --git a/docs/html/defragmentation.html b/docs/html/defragmentation.html index 2d15f36..b0ae912 100644 --- a/docs/html/defragmentation.html +++ b/docs/html/defragmentation.html @@ -132,12 +132,12 @@ Defragmenting CPU memory

    Parameters of VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo().
    Definition: vk_mem_alloc.h:3231
    Represents main object of this library initialized.
    Represents Opaque object that represents started defragmentation process.
    -
    Parameters for defragmentation.
    Definition: vk_mem_alloc.h:3642
    -
    uint32_t allocationCount
    Number of allocations in pAllocations array.
    Definition: vk_mem_alloc.h:3648
    -
    VkBool32 * pAllocationsChanged
    Optional, output. Pointer to array that will be filled with information whether the allocation at cer...
    Definition: vk_mem_alloc.h:3663
    -
    uint32_t maxCpuAllocationsToMove
    Maximum number of allocations that can be moved to a different place using transfers on CPU side,...
    Definition: vk_mem_alloc.h:3692
    -
    const VmaAllocation * pAllocations
    Pointer to array of allocations that can be defragmented.
    Definition: vk_mem_alloc.h:3657
    -
    VkDeviceSize maxCpuBytesToMove
    Maximum total numbers of bytes that can be copied while moving allocations to different places using ...
    Definition: vk_mem_alloc.h:3687
    +
    Parameters for defragmentation.
    Definition: vk_mem_alloc.h:3630
    +
    uint32_t allocationCount
    Number of allocations in pAllocations array.
    Definition: vk_mem_alloc.h:3636
    +
    VkBool32 * pAllocationsChanged
    Optional, output. Pointer to array that will be filled with information whether the allocation at cer...
    Definition: vk_mem_alloc.h:3651
    +
    uint32_t maxCpuAllocationsToMove
    Maximum number of allocations that can be moved to a different place using transfers on CPU side,...
    Definition: vk_mem_alloc.h:3680
    +
    const VmaAllocation * pAllocations
    Pointer to array of allocations that can be defragmented.
    Definition: vk_mem_alloc.h:3645
    +
    VkDeviceSize maxCpuBytesToMove
    Maximum total numbers of bytes that can be copied while moving allocations to different places using ...
    Definition: vk_mem_alloc.h:3675
    VkResult vmaDefragmentationBegin(VmaAllocator allocator, const VmaDefragmentationInfo2 *pInfo, VmaDefragmentationStats *pStats, VmaDefragmentationContext *pContext)
    Begins defragmentation process.
    VkResult vmaBindBufferMemory(VmaAllocator allocator, VmaAllocation allocation, VkBuffer buffer)
    Binds buffer to allocation.
    void vmaGetAllocationInfo(VmaAllocator allocator, VmaAllocation allocation, VmaAllocationInfo *pAllocationInfo)
    Returns current information about specified allocation and atomically marks it as used in current fra...
    @@ -203,9 +203,9 @@ Defragmenting GPU memory
    vmaBindBufferMemory(allocator, allocations[i], buffers[i]);
    }
    }
    -
    uint32_t maxGpuAllocationsToMove
    Maximum number of allocations that can be moved to a different place using transfers on GPU side,...
    Definition: vk_mem_alloc.h:3702
    -
    VkDeviceSize maxGpuBytesToMove
    Maximum total numbers of bytes that can be copied while moving allocations to different places using ...
    Definition: vk_mem_alloc.h:3697
    -
    VkCommandBuffer commandBuffer
    Optional. Command buffer where GPU copy commands will be posted.
    Definition: vk_mem_alloc.h:3711
    +
    uint32_t maxGpuAllocationsToMove
    Maximum number of allocations that can be moved to a different place using transfers on GPU side,...
    Definition: vk_mem_alloc.h:3690
    +
    VkDeviceSize maxGpuBytesToMove
    Maximum total numbers of bytes that can be copied while moving allocations to different places using ...
    Definition: vk_mem_alloc.h:3685
    +
    VkCommandBuffer commandBuffer
    Optional. Command buffer where GPU copy commands will be posted.
    Definition: vk_mem_alloc.h:3699

    You can combine these two methods by specifying non-zero maxGpu* as well as maxCpu* parameters. The library automatically chooses best method to defragment each memory pool.

    You may try not to block your entire program to wait until defragmentation finishes, but do it in the background, as long as you carefully fullfill requirements described in function vmaDefragmentationBegin().

    diff --git a/docs/html/deprecated.html b/docs/html/deprecated.html index d997ede..033bb68 100644 --- a/docs/html/deprecated.html +++ b/docs/html/deprecated.html @@ -67,11 +67,9 @@ $(function() {
    Member vmaDefragment (VmaAllocator allocator, const VmaAllocation *pAllocations, size_t allocationCount, VkBool32 *pAllocationsChanged, const VmaDefragmentationInfo *pDefragmentationInfo, VmaDefragmentationStats *pDefragmentationStats)
    -
    This is a part of the old interface. It is recommended to use structure VmaDefragmentationInfo2 and function vmaDefragmentationBegin() instead.
    +
    This is a part of the old interface. It is recommended to use structure VmaDefragmentationInfo2 and function vmaDefragmentationBegin() instead.
    Member VmaDefragmentationInfo
    -
    This is a part of the old interface. It is recommended to use structure VmaDefragmentationInfo2 and function vmaDefragmentationBegin() instead.
    -
    Member vmaResizeAllocation (VmaAllocator allocator, VmaAllocation allocation, VkDeviceSize newSize)
    -
    In version 2.2.0 it used to try to change allocation's size without moving or reallocating it. In current version it returns VK_SUCCESS only if newSize equals current allocation's size. Otherwise returns VK_ERROR_OUT_OF_POOL_MEMORY, indicating that allocation's size could not be changed.
    +
    This is a part of the old interface. It is recommended to use structure VmaDefragmentationInfo2 and function vmaDefragmentationBegin() instead.
    diff --git a/docs/html/globals.html b/docs/html/globals.html index e5af093..fb5edae 100644 --- a/docs/html/globals.html +++ b/docs/html/globals.html @@ -437,9 +437,6 @@ $(function() {
  • VmaRecordSettings : vk_mem_alloc.h
  • -
  • vmaResizeAllocation() -: vk_mem_alloc.h -
  • vmaSetAllocationUserData() : vk_mem_alloc.h
  • diff --git a/docs/html/globals_func.html b/docs/html/globals_func.html index 8acec30..533bb8d 100644 --- a/docs/html/globals_func.html +++ b/docs/html/globals_func.html @@ -202,9 +202,6 @@ $(function() {
  • vmaMapMemory() : vk_mem_alloc.h
  • -
  • vmaResizeAllocation() -: vk_mem_alloc.h -
  • vmaSetAllocationUserData() : vk_mem_alloc.h
  • diff --git a/docs/html/search/all_11.js b/docs/html/search/all_11.js index fd011a9..75a2986 100644 --- a/docs/html/search/all_11.js +++ b/docs/html/search/all_11.js @@ -138,22 +138,21 @@ var searchData= ['vmamapmemory_220',['vmaMapMemory',['../vk__mem__alloc_8h.html#ad5bd1243512d099706de88168992f069',1,'vk_mem_alloc.h']]], ['vmamemoryusage_221',['VmaMemoryUsage',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cc',1,'VmaMemoryUsage(): vk_mem_alloc.h'],['../vk__mem__alloc_8h.html#a806e8499dde802e59eb72a1dc811c35f',1,'VmaMemoryUsage(): vk_mem_alloc.h']]], ['vmapool_222',['VmaPool',['../struct_vma_pool.html',1,'']]], - ['vmapoolcreateflagbits_223',['VmaPoolCreateFlagBits',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7',1,'VmaPoolCreateFlagBits(): vk_mem_alloc.h'],['../vk__mem__alloc_8h.html#a4d4f2efc2509157a9e4ecd4fd7942303',1,'VmaPoolCreateFlagBits(): vk_mem_alloc.h']]], + ['vmapoolcreateflagbits_223',['VmaPoolCreateFlagBits',['../vk__mem__alloc_8h.html#a4d4f2efc2509157a9e4ecd4fd7942303',1,'VmaPoolCreateFlagBits(): vk_mem_alloc.h'],['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7',1,'VmaPoolCreateFlagBits(): vk_mem_alloc.h']]], ['vmapoolcreateflags_224',['VmaPoolCreateFlags',['../vk__mem__alloc_8h.html#a2770e325ea42e087c1b91fdf46d0292a',1,'vk_mem_alloc.h']]], - ['vmapoolcreateinfo_225',['VmaPoolCreateInfo',['../struct_vma_pool_create_info.html',1,'VmaPoolCreateInfo'],['../vk__mem__alloc_8h.html#a1017aa83489c0eee8d2163d2bf253f67',1,'VmaPoolCreateInfo(): vk_mem_alloc.h']]], + ['vmapoolcreateinfo_225',['VmaPoolCreateInfo',['../vk__mem__alloc_8h.html#a1017aa83489c0eee8d2163d2bf253f67',1,'VmaPoolCreateInfo(): vk_mem_alloc.h'],['../struct_vma_pool_create_info.html',1,'VmaPoolCreateInfo']]], ['vmapoolstats_226',['VmaPoolStats',['../struct_vma_pool_stats.html',1,'VmaPoolStats'],['../vk__mem__alloc_8h.html#a4759a2d9f99c19ba7627553c847132f1',1,'VmaPoolStats(): vk_mem_alloc.h']]], ['vmarecordflagbits_227',['VmaRecordFlagBits',['../vk__mem__alloc_8h.html#a4dd2c44642312a147a4e93373a6e64d2',1,'VmaRecordFlagBits(): vk_mem_alloc.h'],['../vk__mem__alloc_8h.html#acd24d5eb58abff7e1f43cb32a1ba1413',1,'VmaRecordFlagBits(): vk_mem_alloc.h']]], ['vmarecordflags_228',['VmaRecordFlags',['../vk__mem__alloc_8h.html#af3929a1a4547c592fc0b0e55ef452828',1,'vk_mem_alloc.h']]], - ['vmarecordsettings_229',['VmaRecordSettings',['../vk__mem__alloc_8h.html#a16e21c877101493fce582664cd8754fc',1,'VmaRecordSettings(): vk_mem_alloc.h'],['../struct_vma_record_settings.html',1,'VmaRecordSettings']]], - ['vmaresizeallocation_230',['vmaResizeAllocation',['../vk__mem__alloc_8h.html#a0ff488958ca72b28e545880463cb8696',1,'vk_mem_alloc.h']]], - ['vmasetallocationuserdata_231',['vmaSetAllocationUserData',['../vk__mem__alloc_8h.html#af9147d31ffc11d62fc187bde283ed14f',1,'vk_mem_alloc.h']]], - ['vmasetcurrentframeindex_232',['vmaSetCurrentFrameIndex',['../vk__mem__alloc_8h.html#ade56bf8dc9f5a5eaddf5f119ed525236',1,'vk_mem_alloc.h']]], - ['vmasetpoolname_233',['vmaSetPoolName',['../vk__mem__alloc_8h.html#adbae3a0b4ab078024462fc85c37f3b58',1,'vk_mem_alloc.h']]], - ['vmastatinfo_234',['VmaStatInfo',['../struct_vma_stat_info.html',1,'VmaStatInfo'],['../vk__mem__alloc_8h.html#aec5b57e29c97b5d69c6d5654d60df878',1,'VmaStatInfo(): vk_mem_alloc.h']]], - ['vmastats_235',['VmaStats',['../struct_vma_stats.html',1,'VmaStats'],['../vk__mem__alloc_8h.html#a21813b2efdf3836767a9058cd8a94034',1,'VmaStats(): vk_mem_alloc.h']]], - ['vmatouchallocation_236',['vmaTouchAllocation',['../vk__mem__alloc_8h.html#a43d8ba9673c846f049089a5029d5c73a',1,'vk_mem_alloc.h']]], - ['vmaunmapmemory_237',['vmaUnmapMemory',['../vk__mem__alloc_8h.html#a9bc268595cb33f6ec4d519cfce81ff45',1,'vk_mem_alloc.h']]], - ['vmavulkanfunctions_238',['VmaVulkanFunctions',['../struct_vma_vulkan_functions.html',1,'VmaVulkanFunctions'],['../vk__mem__alloc_8h.html#abb0a8e3b5040d847571cca6c7f9a8074',1,'VmaVulkanFunctions(): vk_mem_alloc.h']]], - ['vulkan_20memory_20allocator_239',['Vulkan Memory Allocator',['../index.html',1,'']]], - ['vulkanapiversion_240',['vulkanApiVersion',['../struct_vma_allocator_create_info.html#ae0ffc55139b54520a6bb704b29ffc285',1,'VmaAllocatorCreateInfo']]] + ['vmarecordsettings_229',['VmaRecordSettings',['../struct_vma_record_settings.html',1,'VmaRecordSettings'],['../vk__mem__alloc_8h.html#a16e21c877101493fce582664cd8754fc',1,'VmaRecordSettings(): vk_mem_alloc.h']]], + ['vmasetallocationuserdata_230',['vmaSetAllocationUserData',['../vk__mem__alloc_8h.html#af9147d31ffc11d62fc187bde283ed14f',1,'vk_mem_alloc.h']]], + ['vmasetcurrentframeindex_231',['vmaSetCurrentFrameIndex',['../vk__mem__alloc_8h.html#ade56bf8dc9f5a5eaddf5f119ed525236',1,'vk_mem_alloc.h']]], + ['vmasetpoolname_232',['vmaSetPoolName',['../vk__mem__alloc_8h.html#adbae3a0b4ab078024462fc85c37f3b58',1,'vk_mem_alloc.h']]], + ['vmastatinfo_233',['VmaStatInfo',['../struct_vma_stat_info.html',1,'VmaStatInfo'],['../vk__mem__alloc_8h.html#aec5b57e29c97b5d69c6d5654d60df878',1,'VmaStatInfo(): vk_mem_alloc.h']]], + ['vmastats_234',['VmaStats',['../struct_vma_stats.html',1,'VmaStats'],['../vk__mem__alloc_8h.html#a21813b2efdf3836767a9058cd8a94034',1,'VmaStats(): vk_mem_alloc.h']]], + ['vmatouchallocation_235',['vmaTouchAllocation',['../vk__mem__alloc_8h.html#a43d8ba9673c846f049089a5029d5c73a',1,'vk_mem_alloc.h']]], + ['vmaunmapmemory_236',['vmaUnmapMemory',['../vk__mem__alloc_8h.html#a9bc268595cb33f6ec4d519cfce81ff45',1,'vk_mem_alloc.h']]], + ['vmavulkanfunctions_237',['VmaVulkanFunctions',['../vk__mem__alloc_8h.html#abb0a8e3b5040d847571cca6c7f9a8074',1,'VmaVulkanFunctions(): vk_mem_alloc.h'],['../struct_vma_vulkan_functions.html',1,'VmaVulkanFunctions']]], + ['vulkan_20memory_20allocator_238',['Vulkan Memory Allocator',['../index.html',1,'']]], + ['vulkanapiversion_239',['vulkanApiVersion',['../struct_vma_allocator_create_info.html#ae0ffc55139b54520a6bb704b29ffc285',1,'VmaAllocatorCreateInfo']]] ]; diff --git a/docs/html/search/classes_0.js b/docs/html/search/classes_0.js index 3944cca..f7b0e84 100644 --- a/docs/html/search/classes_0.js +++ b/docs/html/search/classes_0.js @@ -1,24 +1,24 @@ var searchData= [ - ['vmaallocation_241',['VmaAllocation',['../struct_vma_allocation.html',1,'']]], - ['vmaallocationcreateinfo_242',['VmaAllocationCreateInfo',['../struct_vma_allocation_create_info.html',1,'']]], - ['vmaallocationinfo_243',['VmaAllocationInfo',['../struct_vma_allocation_info.html',1,'']]], - ['vmaallocator_244',['VmaAllocator',['../struct_vma_allocator.html',1,'']]], - ['vmaallocatorcreateinfo_245',['VmaAllocatorCreateInfo',['../struct_vma_allocator_create_info.html',1,'']]], - ['vmaallocatorinfo_246',['VmaAllocatorInfo',['../struct_vma_allocator_info.html',1,'']]], - ['vmabudget_247',['VmaBudget',['../struct_vma_budget.html',1,'']]], - ['vmadefragmentationcontext_248',['VmaDefragmentationContext',['../struct_vma_defragmentation_context.html',1,'']]], - ['vmadefragmentationinfo_249',['VmaDefragmentationInfo',['../struct_vma_defragmentation_info.html',1,'']]], - ['vmadefragmentationinfo2_250',['VmaDefragmentationInfo2',['../struct_vma_defragmentation_info2.html',1,'']]], - ['vmadefragmentationpassinfo_251',['VmaDefragmentationPassInfo',['../struct_vma_defragmentation_pass_info.html',1,'']]], - ['vmadefragmentationpassmoveinfo_252',['VmaDefragmentationPassMoveInfo',['../struct_vma_defragmentation_pass_move_info.html',1,'']]], - ['vmadefragmentationstats_253',['VmaDefragmentationStats',['../struct_vma_defragmentation_stats.html',1,'']]], - ['vmadevicememorycallbacks_254',['VmaDeviceMemoryCallbacks',['../struct_vma_device_memory_callbacks.html',1,'']]], - ['vmapool_255',['VmaPool',['../struct_vma_pool.html',1,'']]], - ['vmapoolcreateinfo_256',['VmaPoolCreateInfo',['../struct_vma_pool_create_info.html',1,'']]], - ['vmapoolstats_257',['VmaPoolStats',['../struct_vma_pool_stats.html',1,'']]], - ['vmarecordsettings_258',['VmaRecordSettings',['../struct_vma_record_settings.html',1,'']]], - ['vmastatinfo_259',['VmaStatInfo',['../struct_vma_stat_info.html',1,'']]], - ['vmastats_260',['VmaStats',['../struct_vma_stats.html',1,'']]], - ['vmavulkanfunctions_261',['VmaVulkanFunctions',['../struct_vma_vulkan_functions.html',1,'']]] + ['vmaallocation_240',['VmaAllocation',['../struct_vma_allocation.html',1,'']]], + ['vmaallocationcreateinfo_241',['VmaAllocationCreateInfo',['../struct_vma_allocation_create_info.html',1,'']]], + ['vmaallocationinfo_242',['VmaAllocationInfo',['../struct_vma_allocation_info.html',1,'']]], + ['vmaallocator_243',['VmaAllocator',['../struct_vma_allocator.html',1,'']]], + ['vmaallocatorcreateinfo_244',['VmaAllocatorCreateInfo',['../struct_vma_allocator_create_info.html',1,'']]], + ['vmaallocatorinfo_245',['VmaAllocatorInfo',['../struct_vma_allocator_info.html',1,'']]], + ['vmabudget_246',['VmaBudget',['../struct_vma_budget.html',1,'']]], + ['vmadefragmentationcontext_247',['VmaDefragmentationContext',['../struct_vma_defragmentation_context.html',1,'']]], + ['vmadefragmentationinfo_248',['VmaDefragmentationInfo',['../struct_vma_defragmentation_info.html',1,'']]], + ['vmadefragmentationinfo2_249',['VmaDefragmentationInfo2',['../struct_vma_defragmentation_info2.html',1,'']]], + ['vmadefragmentationpassinfo_250',['VmaDefragmentationPassInfo',['../struct_vma_defragmentation_pass_info.html',1,'']]], + ['vmadefragmentationpassmoveinfo_251',['VmaDefragmentationPassMoveInfo',['../struct_vma_defragmentation_pass_move_info.html',1,'']]], + ['vmadefragmentationstats_252',['VmaDefragmentationStats',['../struct_vma_defragmentation_stats.html',1,'']]], + ['vmadevicememorycallbacks_253',['VmaDeviceMemoryCallbacks',['../struct_vma_device_memory_callbacks.html',1,'']]], + ['vmapool_254',['VmaPool',['../struct_vma_pool.html',1,'']]], + ['vmapoolcreateinfo_255',['VmaPoolCreateInfo',['../struct_vma_pool_create_info.html',1,'']]], + ['vmapoolstats_256',['VmaPoolStats',['../struct_vma_pool_stats.html',1,'']]], + ['vmarecordsettings_257',['VmaRecordSettings',['../struct_vma_record_settings.html',1,'']]], + ['vmastatinfo_258',['VmaStatInfo',['../struct_vma_stat_info.html',1,'']]], + ['vmastats_259',['VmaStats',['../struct_vma_stats.html',1,'']]], + ['vmavulkanfunctions_260',['VmaVulkanFunctions',['../struct_vma_vulkan_functions.html',1,'']]] ]; diff --git a/docs/html/search/defines_0.js b/docs/html/search/defines_0.js index 1f59a46..34117b3 100644 --- a/docs/html/search/defines_0.js +++ b/docs/html/search/defines_0.js @@ -1,11 +1,11 @@ var searchData= [ - ['vma_5fbind_5fmemory2_477',['VMA_BIND_MEMORY2',['../vk__mem__alloc_8h.html#a88bef97f86d70a34a4c0746e09a2680d',1,'vk_mem_alloc.h']]], - ['vma_5fbuffer_5fdevice_5faddress_478',['VMA_BUFFER_DEVICE_ADDRESS',['../vk__mem__alloc_8h.html#a7f9d5e71b70dd1a137c303a8a8262c10',1,'vk_mem_alloc.h']]], - ['vma_5fdedicated_5fallocation_479',['VMA_DEDICATED_ALLOCATION',['../vk__mem__alloc_8h.html#af7b860e63b96d11e44ae8587ba06bbf4',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fbudget_480',['VMA_MEMORY_BUDGET',['../vk__mem__alloc_8h.html#a05decf1cf4ebf767beba7acca6c1ec3a',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fpriority_481',['VMA_MEMORY_PRIORITY',['../vk__mem__alloc_8h.html#a81af8a3a87e34bbb493848143cde43e4',1,'vk_mem_alloc.h']]], - ['vma_5frecording_5fenabled_482',['VMA_RECORDING_ENABLED',['../vk__mem__alloc_8h.html#a1f0c126759fc96ccb6e2d23c101d770c',1,'vk_mem_alloc.h']]], - ['vma_5fstats_5fstring_5fenabled_483',['VMA_STATS_STRING_ENABLED',['../vk__mem__alloc_8h.html#ae25f0d55fd91cb166f002b63244800e1',1,'vk_mem_alloc.h']]], - ['vma_5fvulkan_5fversion_484',['VMA_VULKAN_VERSION',['../vk__mem__alloc_8h.html#a1a2407c283893638cc039bb31fcd74b6',1,'vk_mem_alloc.h']]] + ['vma_5fbind_5fmemory2_475',['VMA_BIND_MEMORY2',['../vk__mem__alloc_8h.html#a88bef97f86d70a34a4c0746e09a2680d',1,'vk_mem_alloc.h']]], + ['vma_5fbuffer_5fdevice_5faddress_476',['VMA_BUFFER_DEVICE_ADDRESS',['../vk__mem__alloc_8h.html#a7f9d5e71b70dd1a137c303a8a8262c10',1,'vk_mem_alloc.h']]], + ['vma_5fdedicated_5fallocation_477',['VMA_DEDICATED_ALLOCATION',['../vk__mem__alloc_8h.html#af7b860e63b96d11e44ae8587ba06bbf4',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fbudget_478',['VMA_MEMORY_BUDGET',['../vk__mem__alloc_8h.html#a05decf1cf4ebf767beba7acca6c1ec3a',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fpriority_479',['VMA_MEMORY_PRIORITY',['../vk__mem__alloc_8h.html#a81af8a3a87e34bbb493848143cde43e4',1,'vk_mem_alloc.h']]], + ['vma_5frecording_5fenabled_480',['VMA_RECORDING_ENABLED',['../vk__mem__alloc_8h.html#a1f0c126759fc96ccb6e2d23c101d770c',1,'vk_mem_alloc.h']]], + ['vma_5fstats_5fstring_5fenabled_481',['VMA_STATS_STRING_ENABLED',['../vk__mem__alloc_8h.html#ae25f0d55fd91cb166f002b63244800e1',1,'vk_mem_alloc.h']]], + ['vma_5fvulkan_5fversion_482',['VMA_VULKAN_VERSION',['../vk__mem__alloc_8h.html#a1a2407c283893638cc039bb31fcd74b6',1,'vk_mem_alloc.h']]] ]; diff --git a/docs/html/search/enums_0.js b/docs/html/search/enums_0.js index b676710..734333c 100644 --- a/docs/html/search/enums_0.js +++ b/docs/html/search/enums_0.js @@ -1,9 +1,9 @@ var searchData= [ - ['vmaallocationcreateflagbits_429',['VmaAllocationCreateFlagBits',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597',1,'vk_mem_alloc.h']]], - ['vmaallocatorcreateflagbits_430',['VmaAllocatorCreateFlagBits',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7c',1,'vk_mem_alloc.h']]], - ['vmadefragmentationflagbits_431',['VmaDefragmentationFlagBits',['../vk__mem__alloc_8h.html#a6552a65b71d16f378c6994b3ceaef50c',1,'vk_mem_alloc.h']]], - ['vmamemoryusage_432',['VmaMemoryUsage',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cc',1,'vk_mem_alloc.h']]], - ['vmapoolcreateflagbits_433',['VmaPoolCreateFlagBits',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7',1,'vk_mem_alloc.h']]], - ['vmarecordflagbits_434',['VmaRecordFlagBits',['../vk__mem__alloc_8h.html#a4dd2c44642312a147a4e93373a6e64d2',1,'vk_mem_alloc.h']]] + ['vmaallocationcreateflagbits_427',['VmaAllocationCreateFlagBits',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597',1,'vk_mem_alloc.h']]], + ['vmaallocatorcreateflagbits_428',['VmaAllocatorCreateFlagBits',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7c',1,'vk_mem_alloc.h']]], + ['vmadefragmentationflagbits_429',['VmaDefragmentationFlagBits',['../vk__mem__alloc_8h.html#a6552a65b71d16f378c6994b3ceaef50c',1,'vk_mem_alloc.h']]], + ['vmamemoryusage_430',['VmaMemoryUsage',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cc',1,'vk_mem_alloc.h']]], + ['vmapoolcreateflagbits_431',['VmaPoolCreateFlagBits',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7',1,'vk_mem_alloc.h']]], + ['vmarecordflagbits_432',['VmaRecordFlagBits',['../vk__mem__alloc_8h.html#a4dd2c44642312a147a4e93373a6e64d2',1,'vk_mem_alloc.h']]] ]; diff --git a/docs/html/search/enumvalues_0.js b/docs/html/search/enumvalues_0.js index 575bac2..74bac7a 100644 --- a/docs/html/search/enumvalues_0.js +++ b/docs/html/search/enumvalues_0.js @@ -1,45 +1,45 @@ var searchData= [ - ['vma_5fallocation_5fcreate_5fcan_5fbecome_5flost_5fbit_435',['VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a5f436af6c8fe8540573a6d22627a6fd2',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fcan_5fmake_5fother_5flost_5fbit_436',['VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a68686d0ce9beb0d4d1b9f2b8b1389a7e',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fdedicated_5fmemory_5fbit_437',['VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a3fc311d855c2ff53f1090ef5c722b38f',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fdont_5fbind_5fbit_438',['VMA_ALLOCATION_CREATE_DONT_BIND_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a2310568c62208af432724305fe29ccea',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fflag_5fbits_5fmax_5fenum_439',['VMA_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597ae5633ec569f4899cf8f29e7385b2f882',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fmapped_5fbit_440',['VMA_ALLOCATION_CREATE_MAPPED_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a11da372cc3a82931c5e5d6146cd9dd1f',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fnever_5fallocate_5fbit_441',['VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a89759603401014eb325eb22a3839f2ff',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fstrategy_5fbest_5ffit_5fbit_442',['VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a839826775c62319466441f86496f036d',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fstrategy_5ffirst_5ffit_5fbit_443',['VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a33eb2052674f3ad92386c714a65fb777',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fstrategy_5fmask_444',['VMA_ALLOCATION_CREATE_STRATEGY_MASK',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a8e16845d81ae3d27c47106d4770d5c7e',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fstrategy_5fmin_5ffragmentation_5fbit_445',['VMA_ALLOCATION_CREATE_STRATEGY_MIN_FRAGMENTATION_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a621b704103eb3360230c860acf36e706',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fstrategy_5fmin_5fmemory_5fbit_446',['VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a8af1210cf591784afa026d94998f735d',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fstrategy_5fmin_5ftime_5fbit_447',['VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a0729e932b7ea170e3a128cad96c5cf6d',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fstrategy_5fworst_5ffit_5fbit_448',['VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597ad242a04f802e25fef0b880afe8bb0a62',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fupper_5faddress_5fbit_449',['VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a42ba3a2d2c7117953210b7c3ef8da0df',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fuser_5fdata_5fcopy_5fstring_5fbit_450',['VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597aa6f24f821cd6a7c5e4a443f7bf59c520',1,'vk_mem_alloc.h']]], - ['vma_5fallocation_5fcreate_5fwithin_5fbudget_5fbit_451',['VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597ab8b1764f3e9022368e440c057783b92d',1,'vk_mem_alloc.h']]], - ['vma_5fallocator_5fcreate_5famd_5fdevice_5fcoherent_5fmemory_5fbit_452',['VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7ca2acce4886d8078552efa38878413970f',1,'vk_mem_alloc.h']]], - ['vma_5fallocator_5fcreate_5fbuffer_5fdevice_5faddress_5fbit_453',['VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7ca5f1b28b0414319d1687e1f2b30ab0089',1,'vk_mem_alloc.h']]], - ['vma_5fallocator_5fcreate_5fext_5fmemory_5fbudget_5fbit_454',['VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7ca4d4687863f7bd4b418c6006dc04400b0',1,'vk_mem_alloc.h']]], - ['vma_5fallocator_5fcreate_5fext_5fmemory_5fpriority_5fbit_455',['VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7caffdd7a5169be3dbd7cbf6b3619e4f78a',1,'vk_mem_alloc.h']]], - ['vma_5fallocator_5fcreate_5fexternally_5fsynchronized_5fbit_456',['VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7ca4816ddaed324ba110172ca608a20f29d',1,'vk_mem_alloc.h']]], - ['vma_5fallocator_5fcreate_5fflag_5fbits_5fmax_5fenum_457',['VMA_ALLOCATOR_CREATE_FLAG_BITS_MAX_ENUM',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7cae4d5ad929caba5f23eb502b13bd5286c',1,'vk_mem_alloc.h']]], - ['vma_5fallocator_5fcreate_5fkhr_5fbind_5fmemory2_5fbit_458',['VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7ca8fb75bf07cd184ab903596295e863dee',1,'vk_mem_alloc.h']]], - ['vma_5fallocator_5fcreate_5fkhr_5fdedicated_5fallocation_5fbit_459',['VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7cace7da7cc6e71a625dfa763c55a597878',1,'vk_mem_alloc.h']]], - ['vma_5fdefragmentation_5fflag_5fbits_5fmax_5fenum_460',['VMA_DEFRAGMENTATION_FLAG_BITS_MAX_ENUM',['../vk__mem__alloc_8h.html#a6552a65b71d16f378c6994b3ceaef50cab87ec33154803bfeb5ac2b379f1d6a97',1,'vk_mem_alloc.h']]], - ['vma_5fdefragmentation_5fflag_5fincremental_461',['VMA_DEFRAGMENTATION_FLAG_INCREMENTAL',['../vk__mem__alloc_8h.html#a6552a65b71d16f378c6994b3ceaef50ca31af49446af2459284a568ce2f3fdd33',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fusage_5fcpu_5fcopy_462',['VMA_MEMORY_USAGE_CPU_COPY',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca416a444d4d0fc20067c3f76f32ff2500',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fusage_5fcpu_5fonly_463',['VMA_MEMORY_USAGE_CPU_ONLY',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca40bdf4cddeffeb12f43d45ca1286e0a5',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fusage_5fcpu_5fto_5fgpu_464',['VMA_MEMORY_USAGE_CPU_TO_GPU',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca9066b52c5a7079bb74a69aaf8b92ff67',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fusage_5fgpu_5flazily_5fallocated_465',['VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca835333d9072db63a653818030e17614d',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fusage_5fgpu_5fonly_466',['VMA_MEMORY_USAGE_GPU_ONLY',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305ccac6b5dc1432d88647aa4cd456246eadf7',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fusage_5fgpu_5fto_5fcpu_467',['VMA_MEMORY_USAGE_GPU_TO_CPU',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca7b586d2fdaf82a463b58f581ed72be27',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fusage_5fmax_5fenum_468',['VMA_MEMORY_USAGE_MAX_ENUM',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca091e69437ef693e8d0d287f1c719ba6e',1,'vk_mem_alloc.h']]], - ['vma_5fmemory_5fusage_5funknown_469',['VMA_MEMORY_USAGE_UNKNOWN',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305ccaf50d27e34e0925cf3a63db8c839121dd',1,'vk_mem_alloc.h']]], - ['vma_5fpool_5fcreate_5falgorithm_5fmask_470',['VMA_POOL_CREATE_ALGORITHM_MASK',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7af4d270f8f42517a0f70037ceb6ac1d9c',1,'vk_mem_alloc.h']]], - ['vma_5fpool_5fcreate_5fbuddy_5falgorithm_5fbit_471',['VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7a97a0dc38e5161b780594d998d313d35e',1,'vk_mem_alloc.h']]], - ['vma_5fpool_5fcreate_5fflag_5fbits_5fmax_5fenum_472',['VMA_POOL_CREATE_FLAG_BITS_MAX_ENUM',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7a1c7312bea9ea246846b9054fd6bd6aec',1,'vk_mem_alloc.h']]], - ['vma_5fpool_5fcreate_5fignore_5fbuffer_5fimage_5fgranularity_5fbit_473',['VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7a9f1a499508a8edb4e8ba40aa0290a3d2',1,'vk_mem_alloc.h']]], - ['vma_5fpool_5fcreate_5flinear_5falgorithm_5fbit_474',['VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7a13c8a444197c67866be9cb05599fc726',1,'vk_mem_alloc.h']]], - ['vma_5frecord_5fflag_5fbits_5fmax_5fenum_475',['VMA_RECORD_FLAG_BITS_MAX_ENUM',['../vk__mem__alloc_8h.html#a4dd2c44642312a147a4e93373a6e64d2a20dd17d69966dbffa054739d6090b85e',1,'vk_mem_alloc.h']]], - ['vma_5frecord_5fflush_5fafter_5fcall_5fbit_476',['VMA_RECORD_FLUSH_AFTER_CALL_BIT',['../vk__mem__alloc_8h.html#a4dd2c44642312a147a4e93373a6e64d2a8e7ab322e8732654be627c4ea8f36cc7',1,'vk_mem_alloc.h']]] + ['vma_5fallocation_5fcreate_5fcan_5fbecome_5flost_5fbit_433',['VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a5f436af6c8fe8540573a6d22627a6fd2',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fcan_5fmake_5fother_5flost_5fbit_434',['VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a68686d0ce9beb0d4d1b9f2b8b1389a7e',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fdedicated_5fmemory_5fbit_435',['VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a3fc311d855c2ff53f1090ef5c722b38f',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fdont_5fbind_5fbit_436',['VMA_ALLOCATION_CREATE_DONT_BIND_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a2310568c62208af432724305fe29ccea',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fflag_5fbits_5fmax_5fenum_437',['VMA_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597ae5633ec569f4899cf8f29e7385b2f882',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fmapped_5fbit_438',['VMA_ALLOCATION_CREATE_MAPPED_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a11da372cc3a82931c5e5d6146cd9dd1f',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fnever_5fallocate_5fbit_439',['VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a89759603401014eb325eb22a3839f2ff',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fstrategy_5fbest_5ffit_5fbit_440',['VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a839826775c62319466441f86496f036d',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fstrategy_5ffirst_5ffit_5fbit_441',['VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a33eb2052674f3ad92386c714a65fb777',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fstrategy_5fmask_442',['VMA_ALLOCATION_CREATE_STRATEGY_MASK',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a8e16845d81ae3d27c47106d4770d5c7e',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fstrategy_5fmin_5ffragmentation_5fbit_443',['VMA_ALLOCATION_CREATE_STRATEGY_MIN_FRAGMENTATION_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a621b704103eb3360230c860acf36e706',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fstrategy_5fmin_5fmemory_5fbit_444',['VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a8af1210cf591784afa026d94998f735d',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fstrategy_5fmin_5ftime_5fbit_445',['VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a0729e932b7ea170e3a128cad96c5cf6d',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fstrategy_5fworst_5ffit_5fbit_446',['VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597ad242a04f802e25fef0b880afe8bb0a62',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fupper_5faddress_5fbit_447',['VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597a42ba3a2d2c7117953210b7c3ef8da0df',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fuser_5fdata_5fcopy_5fstring_5fbit_448',['VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597aa6f24f821cd6a7c5e4a443f7bf59c520',1,'vk_mem_alloc.h']]], + ['vma_5fallocation_5fcreate_5fwithin_5fbudget_5fbit_449',['VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT',['../vk__mem__alloc_8h.html#ad9889c10c798b040d59c92f257cae597ab8b1764f3e9022368e440c057783b92d',1,'vk_mem_alloc.h']]], + ['vma_5fallocator_5fcreate_5famd_5fdevice_5fcoherent_5fmemory_5fbit_450',['VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7ca2acce4886d8078552efa38878413970f',1,'vk_mem_alloc.h']]], + ['vma_5fallocator_5fcreate_5fbuffer_5fdevice_5faddress_5fbit_451',['VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7ca5f1b28b0414319d1687e1f2b30ab0089',1,'vk_mem_alloc.h']]], + ['vma_5fallocator_5fcreate_5fext_5fmemory_5fbudget_5fbit_452',['VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7ca4d4687863f7bd4b418c6006dc04400b0',1,'vk_mem_alloc.h']]], + ['vma_5fallocator_5fcreate_5fext_5fmemory_5fpriority_5fbit_453',['VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7caffdd7a5169be3dbd7cbf6b3619e4f78a',1,'vk_mem_alloc.h']]], + ['vma_5fallocator_5fcreate_5fexternally_5fsynchronized_5fbit_454',['VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7ca4816ddaed324ba110172ca608a20f29d',1,'vk_mem_alloc.h']]], + ['vma_5fallocator_5fcreate_5fflag_5fbits_5fmax_5fenum_455',['VMA_ALLOCATOR_CREATE_FLAG_BITS_MAX_ENUM',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7cae4d5ad929caba5f23eb502b13bd5286c',1,'vk_mem_alloc.h']]], + ['vma_5fallocator_5fcreate_5fkhr_5fbind_5fmemory2_5fbit_456',['VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7ca8fb75bf07cd184ab903596295e863dee',1,'vk_mem_alloc.h']]], + ['vma_5fallocator_5fcreate_5fkhr_5fdedicated_5fallocation_5fbit_457',['VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT',['../vk__mem__alloc_8h.html#a4f87c9100d154a65a4ad495f7763cf7cace7da7cc6e71a625dfa763c55a597878',1,'vk_mem_alloc.h']]], + ['vma_5fdefragmentation_5fflag_5fbits_5fmax_5fenum_458',['VMA_DEFRAGMENTATION_FLAG_BITS_MAX_ENUM',['../vk__mem__alloc_8h.html#a6552a65b71d16f378c6994b3ceaef50cab87ec33154803bfeb5ac2b379f1d6a97',1,'vk_mem_alloc.h']]], + ['vma_5fdefragmentation_5fflag_5fincremental_459',['VMA_DEFRAGMENTATION_FLAG_INCREMENTAL',['../vk__mem__alloc_8h.html#a6552a65b71d16f378c6994b3ceaef50ca31af49446af2459284a568ce2f3fdd33',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fusage_5fcpu_5fcopy_460',['VMA_MEMORY_USAGE_CPU_COPY',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca416a444d4d0fc20067c3f76f32ff2500',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fusage_5fcpu_5fonly_461',['VMA_MEMORY_USAGE_CPU_ONLY',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca40bdf4cddeffeb12f43d45ca1286e0a5',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fusage_5fcpu_5fto_5fgpu_462',['VMA_MEMORY_USAGE_CPU_TO_GPU',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca9066b52c5a7079bb74a69aaf8b92ff67',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fusage_5fgpu_5flazily_5fallocated_463',['VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca835333d9072db63a653818030e17614d',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fusage_5fgpu_5fonly_464',['VMA_MEMORY_USAGE_GPU_ONLY',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305ccac6b5dc1432d88647aa4cd456246eadf7',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fusage_5fgpu_5fto_5fcpu_465',['VMA_MEMORY_USAGE_GPU_TO_CPU',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca7b586d2fdaf82a463b58f581ed72be27',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fusage_5fmax_5fenum_466',['VMA_MEMORY_USAGE_MAX_ENUM',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305cca091e69437ef693e8d0d287f1c719ba6e',1,'vk_mem_alloc.h']]], + ['vma_5fmemory_5fusage_5funknown_467',['VMA_MEMORY_USAGE_UNKNOWN',['../vk__mem__alloc_8h.html#aa5846affa1e9da3800e3e78fae2305ccaf50d27e34e0925cf3a63db8c839121dd',1,'vk_mem_alloc.h']]], + ['vma_5fpool_5fcreate_5falgorithm_5fmask_468',['VMA_POOL_CREATE_ALGORITHM_MASK',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7af4d270f8f42517a0f70037ceb6ac1d9c',1,'vk_mem_alloc.h']]], + ['vma_5fpool_5fcreate_5fbuddy_5falgorithm_5fbit_469',['VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7a97a0dc38e5161b780594d998d313d35e',1,'vk_mem_alloc.h']]], + ['vma_5fpool_5fcreate_5fflag_5fbits_5fmax_5fenum_470',['VMA_POOL_CREATE_FLAG_BITS_MAX_ENUM',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7a1c7312bea9ea246846b9054fd6bd6aec',1,'vk_mem_alloc.h']]], + ['vma_5fpool_5fcreate_5fignore_5fbuffer_5fimage_5fgranularity_5fbit_471',['VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7a9f1a499508a8edb4e8ba40aa0290a3d2',1,'vk_mem_alloc.h']]], + ['vma_5fpool_5fcreate_5flinear_5falgorithm_5fbit_472',['VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT',['../vk__mem__alloc_8h.html#a9a7c45f9c863695d98c83fa5ac940fe7a13c8a444197c67866be9cb05599fc726',1,'vk_mem_alloc.h']]], + ['vma_5frecord_5fflag_5fbits_5fmax_5fenum_473',['VMA_RECORD_FLAG_BITS_MAX_ENUM',['../vk__mem__alloc_8h.html#a4dd2c44642312a147a4e93373a6e64d2a20dd17d69966dbffa054739d6090b85e',1,'vk_mem_alloc.h']]], + ['vma_5frecord_5fflush_5fafter_5fcall_5fbit_474',['VMA_RECORD_FLUSH_AFTER_CALL_BIT',['../vk__mem__alloc_8h.html#a4dd2c44642312a147a4e93373a6e64d2a8e7ab322e8732654be627c4ea8f36cc7',1,'vk_mem_alloc.h']]] ]; diff --git a/docs/html/search/files_0.js b/docs/html/search/files_0.js index bcac042..10428fd 100644 --- a/docs/html/search/files_0.js +++ b/docs/html/search/files_0.js @@ -1,4 +1,4 @@ var searchData= [ - ['vk_5fmem_5falloc_2eh_262',['vk_mem_alloc.h',['../vk__mem__alloc_8h.html',1,'']]] + ['vk_5fmem_5falloc_2eh_261',['vk_mem_alloc.h',['../vk__mem__alloc_8h.html',1,'']]] ]; diff --git a/docs/html/search/functions_0.js b/docs/html/search/functions_0.js index 4afcbd2..6940455 100644 --- a/docs/html/search/functions_0.js +++ b/docs/html/search/functions_0.js @@ -1,55 +1,54 @@ var searchData= [ - ['vmaallocatememory_263',['vmaAllocateMemory',['../vk__mem__alloc_8h.html#abf28077dbf82d0908b8acbe8ee8dd9b8',1,'vk_mem_alloc.h']]], - ['vmaallocatememoryforbuffer_264',['vmaAllocateMemoryForBuffer',['../vk__mem__alloc_8h.html#a7fdf64415b6c3d83c454f28d2c53df7b',1,'vk_mem_alloc.h']]], - ['vmaallocatememoryforimage_265',['vmaAllocateMemoryForImage',['../vk__mem__alloc_8h.html#a0faa3f9e5fb233d29d1e00390650febb',1,'vk_mem_alloc.h']]], - ['vmaallocatememorypages_266',['vmaAllocateMemoryPages',['../vk__mem__alloc_8h.html#ad37e82e492b3de38fc3f4cffd9ad0ae1',1,'vk_mem_alloc.h']]], - ['vmabegindefragmentationpass_267',['vmaBeginDefragmentationPass',['../vk__mem__alloc_8h.html#ac0f01545b6262f7d4d128fc8f8e5c77b',1,'vk_mem_alloc.h']]], - ['vmabindbuffermemory_268',['vmaBindBufferMemory',['../vk__mem__alloc_8h.html#a6b0929b914b60cf2d45cac4bf3547470',1,'vk_mem_alloc.h']]], - ['vmabindbuffermemory2_269',['vmaBindBufferMemory2',['../vk__mem__alloc_8h.html#a927c944f45e0f2941182abb6f608e64a',1,'vk_mem_alloc.h']]], - ['vmabindimagememory_270',['vmaBindImageMemory',['../vk__mem__alloc_8h.html#a3d3ca45799923aa5d138e9e5f9eb2da5',1,'vk_mem_alloc.h']]], - ['vmabindimagememory2_271',['vmaBindImageMemory2',['../vk__mem__alloc_8h.html#aa8251ee81b0045a443e35b8e8aa021bc',1,'vk_mem_alloc.h']]], - ['vmabuildstatsstring_272',['vmaBuildStatsString',['../vk__mem__alloc_8h.html#aa4fee7eb5253377599ef4fd38c93c2a0',1,'vk_mem_alloc.h']]], - ['vmacalculatestats_273',['vmaCalculateStats',['../vk__mem__alloc_8h.html#a333b61c1788cb23559177531e6a93ca3',1,'vk_mem_alloc.h']]], - ['vmacheckcorruption_274',['vmaCheckCorruption',['../vk__mem__alloc_8h.html#a49329a7f030dafcf82f7b73334c22e98',1,'vk_mem_alloc.h']]], - ['vmacheckpoolcorruption_275',['vmaCheckPoolCorruption',['../vk__mem__alloc_8h.html#ad535935619c7a549bf837e1bb0068f89',1,'vk_mem_alloc.h']]], - ['vmacreateallocator_276',['vmaCreateAllocator',['../vk__mem__alloc_8h.html#a200692051ddb34240248234f5f4c17bb',1,'vk_mem_alloc.h']]], - ['vmacreatebuffer_277',['vmaCreateBuffer',['../vk__mem__alloc_8h.html#ac72ee55598617e8eecca384e746bab51',1,'vk_mem_alloc.h']]], - ['vmacreateimage_278',['vmaCreateImage',['../vk__mem__alloc_8h.html#a02a94f25679275851a53e82eacbcfc73',1,'vk_mem_alloc.h']]], - ['vmacreatelostallocation_279',['vmaCreateLostAllocation',['../vk__mem__alloc_8h.html#ae5c9657d9e94756269145b01c05d16f1',1,'vk_mem_alloc.h']]], - ['vmacreatepool_280',['vmaCreatePool',['../vk__mem__alloc_8h.html#a5c8770ded7c59c8caac6de0c2cb00b50',1,'vk_mem_alloc.h']]], - ['vmadefragment_281',['vmaDefragment',['../vk__mem__alloc_8h.html#a9f0f8f56db5f7f57fe4454f465142dac',1,'vk_mem_alloc.h']]], - ['vmadefragmentationbegin_282',['vmaDefragmentationBegin',['../vk__mem__alloc_8h.html#a36ba776fd7fd5cb1e9359fdc0d8e6e8a',1,'vk_mem_alloc.h']]], - ['vmadefragmentationend_283',['vmaDefragmentationEnd',['../vk__mem__alloc_8h.html#a8774e20e91e245aae959ba63efa15dd2',1,'vk_mem_alloc.h']]], - ['vmadestroyallocator_284',['vmaDestroyAllocator',['../vk__mem__alloc_8h.html#aa8d164061c88f22fb1fd3c8f3534bc1d',1,'vk_mem_alloc.h']]], - ['vmadestroybuffer_285',['vmaDestroyBuffer',['../vk__mem__alloc_8h.html#a0d9f4e4ba5bf9aab1f1c746387753d77',1,'vk_mem_alloc.h']]], - ['vmadestroyimage_286',['vmaDestroyImage',['../vk__mem__alloc_8h.html#ae50d2cb3b4a3bfd4dd40987234e50e7e',1,'vk_mem_alloc.h']]], - ['vmadestroypool_287',['vmaDestroyPool',['../vk__mem__alloc_8h.html#a5485779c8f1948238fc4e92232fa65e1',1,'vk_mem_alloc.h']]], - ['vmaenddefragmentationpass_288',['vmaEndDefragmentationPass',['../vk__mem__alloc_8h.html#a1b9ffa538bed905af55c747cc48963bd',1,'vk_mem_alloc.h']]], - ['vmafindmemorytypeindex_289',['vmaFindMemoryTypeIndex',['../vk__mem__alloc_8h.html#aef15a94b58fbcb0fe706d5720e84a74a',1,'vk_mem_alloc.h']]], - ['vmafindmemorytypeindexforbufferinfo_290',['vmaFindMemoryTypeIndexForBufferInfo',['../vk__mem__alloc_8h.html#ae790ab9ffaf7667fb8f62523e6897888',1,'vk_mem_alloc.h']]], - ['vmafindmemorytypeindexforimageinfo_291',['vmaFindMemoryTypeIndexForImageInfo',['../vk__mem__alloc_8h.html#a088da83d8eaf3ce9056d9ea0b981d472',1,'vk_mem_alloc.h']]], - ['vmaflushallocation_292',['vmaFlushAllocation',['../vk__mem__alloc_8h.html#a30c37c1eec6025f397be41644f48490f',1,'vk_mem_alloc.h']]], - ['vmaflushallocations_293',['vmaFlushAllocations',['../vk__mem__alloc_8h.html#ac3dd00da721875ed99fa8a881922bdfc',1,'vk_mem_alloc.h']]], - ['vmafreememory_294',['vmaFreeMemory',['../vk__mem__alloc_8h.html#a5fea5518972ae9094b1526cbcb19b05f',1,'vk_mem_alloc.h']]], - ['vmafreememorypages_295',['vmaFreeMemoryPages',['../vk__mem__alloc_8h.html#a834b1e4aef395c0a1d56a28e69a4a17e',1,'vk_mem_alloc.h']]], - ['vmafreestatsstring_296',['vmaFreeStatsString',['../vk__mem__alloc_8h.html#a3104eb30d8122c84dd8541063f145288',1,'vk_mem_alloc.h']]], - ['vmagetallocationinfo_297',['vmaGetAllocationInfo',['../vk__mem__alloc_8h.html#a86dd08aba8633bfa4ad0df2e76481d8b',1,'vk_mem_alloc.h']]], - ['vmagetallocatorinfo_298',['vmaGetAllocatorInfo',['../vk__mem__alloc_8h.html#afa02231a791b37255720d566a52683e7',1,'vk_mem_alloc.h']]], - ['vmagetbudget_299',['vmaGetBudget',['../vk__mem__alloc_8h.html#aec0ed24ebea2d0099eed5f801daaefba',1,'vk_mem_alloc.h']]], - ['vmagetmemoryproperties_300',['vmaGetMemoryProperties',['../vk__mem__alloc_8h.html#ab88db292a17974f911182543fda52d19',1,'vk_mem_alloc.h']]], - ['vmagetmemorytypeproperties_301',['vmaGetMemoryTypeProperties',['../vk__mem__alloc_8h.html#a8701444752eb5de4464adb5a2b514bca',1,'vk_mem_alloc.h']]], - ['vmagetphysicaldeviceproperties_302',['vmaGetPhysicalDeviceProperties',['../vk__mem__alloc_8h.html#aecabf7b6e91ea87d0316fa0a9e014fe0',1,'vk_mem_alloc.h']]], - ['vmagetpoolname_303',['vmaGetPoolName',['../vk__mem__alloc_8h.html#af09b4e4eafdbee812e8d73ddf960f030',1,'vk_mem_alloc.h']]], - ['vmagetpoolstats_304',['vmaGetPoolStats',['../vk__mem__alloc_8h.html#ae8bf76997b234ef68aad922616df4153',1,'vk_mem_alloc.h']]], - ['vmainvalidateallocation_305',['vmaInvalidateAllocation',['../vk__mem__alloc_8h.html#aaa8412919139ef413a4215ac6a290fae',1,'vk_mem_alloc.h']]], - ['vmainvalidateallocations_306',['vmaInvalidateAllocations',['../vk__mem__alloc_8h.html#ab25b558d75f7378ec944a1522fdcc3c5',1,'vk_mem_alloc.h']]], - ['vmamakepoolallocationslost_307',['vmaMakePoolAllocationsLost',['../vk__mem__alloc_8h.html#a736bd6cbda886f36c891727e73bd4024',1,'vk_mem_alloc.h']]], - ['vmamapmemory_308',['vmaMapMemory',['../vk__mem__alloc_8h.html#ad5bd1243512d099706de88168992f069',1,'vk_mem_alloc.h']]], - ['vmaresizeallocation_309',['vmaResizeAllocation',['../vk__mem__alloc_8h.html#a0ff488958ca72b28e545880463cb8696',1,'vk_mem_alloc.h']]], - ['vmasetallocationuserdata_310',['vmaSetAllocationUserData',['../vk__mem__alloc_8h.html#af9147d31ffc11d62fc187bde283ed14f',1,'vk_mem_alloc.h']]], - ['vmasetcurrentframeindex_311',['vmaSetCurrentFrameIndex',['../vk__mem__alloc_8h.html#ade56bf8dc9f5a5eaddf5f119ed525236',1,'vk_mem_alloc.h']]], - ['vmasetpoolname_312',['vmaSetPoolName',['../vk__mem__alloc_8h.html#adbae3a0b4ab078024462fc85c37f3b58',1,'vk_mem_alloc.h']]], - ['vmatouchallocation_313',['vmaTouchAllocation',['../vk__mem__alloc_8h.html#a43d8ba9673c846f049089a5029d5c73a',1,'vk_mem_alloc.h']]], - ['vmaunmapmemory_314',['vmaUnmapMemory',['../vk__mem__alloc_8h.html#a9bc268595cb33f6ec4d519cfce81ff45',1,'vk_mem_alloc.h']]] + ['vmaallocatememory_262',['vmaAllocateMemory',['../vk__mem__alloc_8h.html#abf28077dbf82d0908b8acbe8ee8dd9b8',1,'vk_mem_alloc.h']]], + ['vmaallocatememoryforbuffer_263',['vmaAllocateMemoryForBuffer',['../vk__mem__alloc_8h.html#a7fdf64415b6c3d83c454f28d2c53df7b',1,'vk_mem_alloc.h']]], + ['vmaallocatememoryforimage_264',['vmaAllocateMemoryForImage',['../vk__mem__alloc_8h.html#a0faa3f9e5fb233d29d1e00390650febb',1,'vk_mem_alloc.h']]], + ['vmaallocatememorypages_265',['vmaAllocateMemoryPages',['../vk__mem__alloc_8h.html#ad37e82e492b3de38fc3f4cffd9ad0ae1',1,'vk_mem_alloc.h']]], + ['vmabegindefragmentationpass_266',['vmaBeginDefragmentationPass',['../vk__mem__alloc_8h.html#ac0f01545b6262f7d4d128fc8f8e5c77b',1,'vk_mem_alloc.h']]], + ['vmabindbuffermemory_267',['vmaBindBufferMemory',['../vk__mem__alloc_8h.html#a6b0929b914b60cf2d45cac4bf3547470',1,'vk_mem_alloc.h']]], + ['vmabindbuffermemory2_268',['vmaBindBufferMemory2',['../vk__mem__alloc_8h.html#a927c944f45e0f2941182abb6f608e64a',1,'vk_mem_alloc.h']]], + ['vmabindimagememory_269',['vmaBindImageMemory',['../vk__mem__alloc_8h.html#a3d3ca45799923aa5d138e9e5f9eb2da5',1,'vk_mem_alloc.h']]], + ['vmabindimagememory2_270',['vmaBindImageMemory2',['../vk__mem__alloc_8h.html#aa8251ee81b0045a443e35b8e8aa021bc',1,'vk_mem_alloc.h']]], + ['vmabuildstatsstring_271',['vmaBuildStatsString',['../vk__mem__alloc_8h.html#aa4fee7eb5253377599ef4fd38c93c2a0',1,'vk_mem_alloc.h']]], + ['vmacalculatestats_272',['vmaCalculateStats',['../vk__mem__alloc_8h.html#a333b61c1788cb23559177531e6a93ca3',1,'vk_mem_alloc.h']]], + ['vmacheckcorruption_273',['vmaCheckCorruption',['../vk__mem__alloc_8h.html#a49329a7f030dafcf82f7b73334c22e98',1,'vk_mem_alloc.h']]], + ['vmacheckpoolcorruption_274',['vmaCheckPoolCorruption',['../vk__mem__alloc_8h.html#ad535935619c7a549bf837e1bb0068f89',1,'vk_mem_alloc.h']]], + ['vmacreateallocator_275',['vmaCreateAllocator',['../vk__mem__alloc_8h.html#a200692051ddb34240248234f5f4c17bb',1,'vk_mem_alloc.h']]], + ['vmacreatebuffer_276',['vmaCreateBuffer',['../vk__mem__alloc_8h.html#ac72ee55598617e8eecca384e746bab51',1,'vk_mem_alloc.h']]], + ['vmacreateimage_277',['vmaCreateImage',['../vk__mem__alloc_8h.html#a02a94f25679275851a53e82eacbcfc73',1,'vk_mem_alloc.h']]], + ['vmacreatelostallocation_278',['vmaCreateLostAllocation',['../vk__mem__alloc_8h.html#ae5c9657d9e94756269145b01c05d16f1',1,'vk_mem_alloc.h']]], + ['vmacreatepool_279',['vmaCreatePool',['../vk__mem__alloc_8h.html#a5c8770ded7c59c8caac6de0c2cb00b50',1,'vk_mem_alloc.h']]], + ['vmadefragment_280',['vmaDefragment',['../vk__mem__alloc_8h.html#a9f0f8f56db5f7f57fe4454f465142dac',1,'vk_mem_alloc.h']]], + ['vmadefragmentationbegin_281',['vmaDefragmentationBegin',['../vk__mem__alloc_8h.html#a36ba776fd7fd5cb1e9359fdc0d8e6e8a',1,'vk_mem_alloc.h']]], + ['vmadefragmentationend_282',['vmaDefragmentationEnd',['../vk__mem__alloc_8h.html#a8774e20e91e245aae959ba63efa15dd2',1,'vk_mem_alloc.h']]], + ['vmadestroyallocator_283',['vmaDestroyAllocator',['../vk__mem__alloc_8h.html#aa8d164061c88f22fb1fd3c8f3534bc1d',1,'vk_mem_alloc.h']]], + ['vmadestroybuffer_284',['vmaDestroyBuffer',['../vk__mem__alloc_8h.html#a0d9f4e4ba5bf9aab1f1c746387753d77',1,'vk_mem_alloc.h']]], + ['vmadestroyimage_285',['vmaDestroyImage',['../vk__mem__alloc_8h.html#ae50d2cb3b4a3bfd4dd40987234e50e7e',1,'vk_mem_alloc.h']]], + ['vmadestroypool_286',['vmaDestroyPool',['../vk__mem__alloc_8h.html#a5485779c8f1948238fc4e92232fa65e1',1,'vk_mem_alloc.h']]], + ['vmaenddefragmentationpass_287',['vmaEndDefragmentationPass',['../vk__mem__alloc_8h.html#a1b9ffa538bed905af55c747cc48963bd',1,'vk_mem_alloc.h']]], + ['vmafindmemorytypeindex_288',['vmaFindMemoryTypeIndex',['../vk__mem__alloc_8h.html#aef15a94b58fbcb0fe706d5720e84a74a',1,'vk_mem_alloc.h']]], + ['vmafindmemorytypeindexforbufferinfo_289',['vmaFindMemoryTypeIndexForBufferInfo',['../vk__mem__alloc_8h.html#ae790ab9ffaf7667fb8f62523e6897888',1,'vk_mem_alloc.h']]], + ['vmafindmemorytypeindexforimageinfo_290',['vmaFindMemoryTypeIndexForImageInfo',['../vk__mem__alloc_8h.html#a088da83d8eaf3ce9056d9ea0b981d472',1,'vk_mem_alloc.h']]], + ['vmaflushallocation_291',['vmaFlushAllocation',['../vk__mem__alloc_8h.html#a30c37c1eec6025f397be41644f48490f',1,'vk_mem_alloc.h']]], + ['vmaflushallocations_292',['vmaFlushAllocations',['../vk__mem__alloc_8h.html#ac3dd00da721875ed99fa8a881922bdfc',1,'vk_mem_alloc.h']]], + ['vmafreememory_293',['vmaFreeMemory',['../vk__mem__alloc_8h.html#a5fea5518972ae9094b1526cbcb19b05f',1,'vk_mem_alloc.h']]], + ['vmafreememorypages_294',['vmaFreeMemoryPages',['../vk__mem__alloc_8h.html#a834b1e4aef395c0a1d56a28e69a4a17e',1,'vk_mem_alloc.h']]], + ['vmafreestatsstring_295',['vmaFreeStatsString',['../vk__mem__alloc_8h.html#a3104eb30d8122c84dd8541063f145288',1,'vk_mem_alloc.h']]], + ['vmagetallocationinfo_296',['vmaGetAllocationInfo',['../vk__mem__alloc_8h.html#a86dd08aba8633bfa4ad0df2e76481d8b',1,'vk_mem_alloc.h']]], + ['vmagetallocatorinfo_297',['vmaGetAllocatorInfo',['../vk__mem__alloc_8h.html#afa02231a791b37255720d566a52683e7',1,'vk_mem_alloc.h']]], + ['vmagetbudget_298',['vmaGetBudget',['../vk__mem__alloc_8h.html#aec0ed24ebea2d0099eed5f801daaefba',1,'vk_mem_alloc.h']]], + ['vmagetmemoryproperties_299',['vmaGetMemoryProperties',['../vk__mem__alloc_8h.html#ab88db292a17974f911182543fda52d19',1,'vk_mem_alloc.h']]], + ['vmagetmemorytypeproperties_300',['vmaGetMemoryTypeProperties',['../vk__mem__alloc_8h.html#a8701444752eb5de4464adb5a2b514bca',1,'vk_mem_alloc.h']]], + ['vmagetphysicaldeviceproperties_301',['vmaGetPhysicalDeviceProperties',['../vk__mem__alloc_8h.html#aecabf7b6e91ea87d0316fa0a9e014fe0',1,'vk_mem_alloc.h']]], + ['vmagetpoolname_302',['vmaGetPoolName',['../vk__mem__alloc_8h.html#af09b4e4eafdbee812e8d73ddf960f030',1,'vk_mem_alloc.h']]], + ['vmagetpoolstats_303',['vmaGetPoolStats',['../vk__mem__alloc_8h.html#ae8bf76997b234ef68aad922616df4153',1,'vk_mem_alloc.h']]], + ['vmainvalidateallocation_304',['vmaInvalidateAllocation',['../vk__mem__alloc_8h.html#aaa8412919139ef413a4215ac6a290fae',1,'vk_mem_alloc.h']]], + ['vmainvalidateallocations_305',['vmaInvalidateAllocations',['../vk__mem__alloc_8h.html#ab25b558d75f7378ec944a1522fdcc3c5',1,'vk_mem_alloc.h']]], + ['vmamakepoolallocationslost_306',['vmaMakePoolAllocationsLost',['../vk__mem__alloc_8h.html#a736bd6cbda886f36c891727e73bd4024',1,'vk_mem_alloc.h']]], + ['vmamapmemory_307',['vmaMapMemory',['../vk__mem__alloc_8h.html#ad5bd1243512d099706de88168992f069',1,'vk_mem_alloc.h']]], + ['vmasetallocationuserdata_308',['vmaSetAllocationUserData',['../vk__mem__alloc_8h.html#af9147d31ffc11d62fc187bde283ed14f',1,'vk_mem_alloc.h']]], + ['vmasetcurrentframeindex_309',['vmaSetCurrentFrameIndex',['../vk__mem__alloc_8h.html#ade56bf8dc9f5a5eaddf5f119ed525236',1,'vk_mem_alloc.h']]], + ['vmasetpoolname_310',['vmaSetPoolName',['../vk__mem__alloc_8h.html#adbae3a0b4ab078024462fc85c37f3b58',1,'vk_mem_alloc.h']]], + ['vmatouchallocation_311',['vmaTouchAllocation',['../vk__mem__alloc_8h.html#a43d8ba9673c846f049089a5029d5c73a',1,'vk_mem_alloc.h']]], + ['vmaunmapmemory_312',['vmaUnmapMemory',['../vk__mem__alloc_8h.html#a9bc268595cb33f6ec4d519cfce81ff45',1,'vk_mem_alloc.h']]] ]; diff --git a/docs/html/search/pages_0.js b/docs/html/search/pages_0.js index b317590..25ac023 100644 --- a/docs/html/search/pages_0.js +++ b/docs/html/search/pages_0.js @@ -1,4 +1,4 @@ var searchData= [ - ['allocation_20names_20and_20user_20data_485',['Allocation names and user data',['../allocation_annotation.html',1,'index']]] + ['allocation_20names_20and_20user_20data_483',['Allocation names and user data',['../allocation_annotation.html',1,'index']]] ]; diff --git a/docs/html/search/pages_1.js b/docs/html/search/pages_1.js index f6dd8a9..bc544e5 100644 --- a/docs/html/search/pages_1.js +++ b/docs/html/search/pages_1.js @@ -1,6 +1,6 @@ var searchData= [ - ['choosing_20memory_20type_486',['Choosing memory type',['../choosing_memory_type.html',1,'index']]], - ['configuration_487',['Configuration',['../configuration.html',1,'index']]], - ['custom_20memory_20pools_488',['Custom memory pools',['../custom_memory_pools.html',1,'index']]] + ['choosing_20memory_20type_484',['Choosing memory type',['../choosing_memory_type.html',1,'index']]], + ['configuration_485',['Configuration',['../configuration.html',1,'index']]], + ['custom_20memory_20pools_486',['Custom memory pools',['../custom_memory_pools.html',1,'index']]] ]; diff --git a/docs/html/search/pages_2.js b/docs/html/search/pages_2.js index eec09ef..a3326f9 100644 --- a/docs/html/search/pages_2.js +++ b/docs/html/search/pages_2.js @@ -1,6 +1,6 @@ var searchData= [ - ['debugging_20incorrect_20memory_20usage_489',['Debugging incorrect memory usage',['../debugging_memory_usage.html',1,'index']]], - ['defragmentation_490',['Defragmentation',['../defragmentation.html',1,'index']]], - ['deprecated_20list_491',['Deprecated List',['../deprecated.html',1,'']]] + ['debugging_20incorrect_20memory_20usage_487',['Debugging incorrect memory usage',['../debugging_memory_usage.html',1,'index']]], + ['defragmentation_488',['Defragmentation',['../defragmentation.html',1,'index']]], + ['deprecated_20list_489',['Deprecated List',['../deprecated.html',1,'']]] ]; diff --git a/docs/html/search/pages_3.js b/docs/html/search/pages_3.js index e2a1445..6d55588 100644 --- a/docs/html/search/pages_3.js +++ b/docs/html/search/pages_3.js @@ -1,4 +1,4 @@ var searchData= [ - ['enabling_20buffer_20device_20address_492',['Enabling buffer device address',['../enabling_buffer_device_address.html',1,'index']]] + ['enabling_20buffer_20device_20address_490',['Enabling buffer device address',['../enabling_buffer_device_address.html',1,'index']]] ]; diff --git a/docs/html/search/pages_4.js b/docs/html/search/pages_4.js index 19c7b4a..24152c1 100644 --- a/docs/html/search/pages_4.js +++ b/docs/html/search/pages_4.js @@ -1,4 +1,4 @@ var searchData= [ - ['general_20considerations_493',['General considerations',['../general_considerations.html',1,'index']]] + ['general_20considerations_491',['General considerations',['../general_considerations.html',1,'index']]] ]; diff --git a/docs/html/search/pages_5.js b/docs/html/search/pages_5.js index d827ca2..3fb7c9e 100644 --- a/docs/html/search/pages_5.js +++ b/docs/html/search/pages_5.js @@ -1,4 +1,4 @@ var searchData= [ - ['lost_20allocations_494',['Lost allocations',['../lost_allocations.html',1,'index']]] + ['lost_20allocations_492',['Lost allocations',['../lost_allocations.html',1,'index']]] ]; diff --git a/docs/html/search/pages_6.js b/docs/html/search/pages_6.js index 92ae94e..90c7a07 100644 --- a/docs/html/search/pages_6.js +++ b/docs/html/search/pages_6.js @@ -1,4 +1,4 @@ var searchData= [ - ['memory_20mapping_495',['Memory mapping',['../memory_mapping.html',1,'index']]] + ['memory_20mapping_493',['Memory mapping',['../memory_mapping.html',1,'index']]] ]; diff --git a/docs/html/search/pages_7.js b/docs/html/search/pages_7.js index 349a27c..ea54719 100644 --- a/docs/html/search/pages_7.js +++ b/docs/html/search/pages_7.js @@ -1,4 +1,4 @@ var searchData= [ - ['quick_20start_496',['Quick start',['../quick_start.html',1,'index']]] + ['quick_20start_494',['Quick start',['../quick_start.html',1,'index']]] ]; diff --git a/docs/html/search/pages_8.js b/docs/html/search/pages_8.js index a1962ed..348ea46 100644 --- a/docs/html/search/pages_8.js +++ b/docs/html/search/pages_8.js @@ -1,6 +1,6 @@ var searchData= [ - ['recommended_20usage_20patterns_497',['Recommended usage patterns',['../usage_patterns.html',1,'index']]], - ['record_20and_20replay_498',['Record and replay',['../record_and_replay.html',1,'index']]], - ['resource_20aliasing_20_28overlap_29_499',['Resource aliasing (overlap)',['../resource_aliasing.html',1,'index']]] + ['recommended_20usage_20patterns_495',['Recommended usage patterns',['../usage_patterns.html',1,'index']]], + ['record_20and_20replay_496',['Record and replay',['../record_and_replay.html',1,'index']]], + ['resource_20aliasing_20_28overlap_29_497',['Resource aliasing (overlap)',['../resource_aliasing.html',1,'index']]] ]; diff --git a/docs/html/search/pages_9.js b/docs/html/search/pages_9.js index 4c218b5..e9d588e 100644 --- a/docs/html/search/pages_9.js +++ b/docs/html/search/pages_9.js @@ -1,5 +1,5 @@ var searchData= [ - ['statistics_500',['Statistics',['../statistics.html',1,'index']]], - ['staying_20within_20budget_501',['Staying within budget',['../staying_within_budget.html',1,'index']]] + ['statistics_498',['Statistics',['../statistics.html',1,'index']]], + ['staying_20within_20budget_499',['Staying within budget',['../staying_within_budget.html',1,'index']]] ]; diff --git a/docs/html/search/pages_a.js b/docs/html/search/pages_a.js index c356f50..bf4af17 100644 --- a/docs/html/search/pages_a.js +++ b/docs/html/search/pages_a.js @@ -1,6 +1,6 @@ var searchData= [ - ['vk_5famd_5fdevice_5fcoherent_5fmemory_502',['VK_AMD_device_coherent_memory',['../vk_amd_device_coherent_memory.html',1,'index']]], - ['vk_5fkhr_5fdedicated_5fallocation_503',['VK_KHR_dedicated_allocation',['../vk_khr_dedicated_allocation.html',1,'index']]], - ['vulkan_20memory_20allocator_504',['Vulkan Memory Allocator',['../index.html',1,'']]] + ['vk_5famd_5fdevice_5fcoherent_5fmemory_500',['VK_AMD_device_coherent_memory',['../vk_amd_device_coherent_memory.html',1,'index']]], + ['vk_5fkhr_5fdedicated_5fallocation_501',['VK_KHR_dedicated_allocation',['../vk_khr_dedicated_allocation.html',1,'index']]], + ['vulkan_20memory_20allocator_502',['Vulkan Memory Allocator',['../index.html',1,'']]] ]; diff --git a/docs/html/search/typedefs_0.js b/docs/html/search/typedefs_0.js index 1f52652..25302c7 100644 --- a/docs/html/search/typedefs_0.js +++ b/docs/html/search/typedefs_0.js @@ -1,5 +1,5 @@ var searchData= [ - ['pfn_5fvmaallocatedevicememoryfunction_399',['PFN_vmaAllocateDeviceMemoryFunction',['../vk__mem__alloc_8h.html#a7e1ed85f7799600b03ad51a77acc21f3',1,'vk_mem_alloc.h']]], - ['pfn_5fvmafreedevicememoryfunction_400',['PFN_vmaFreeDeviceMemoryFunction',['../vk__mem__alloc_8h.html#a154ccaaf53dc2c36378f80f0c4f3679b',1,'vk_mem_alloc.h']]] + ['pfn_5fvmaallocatedevicememoryfunction_397',['PFN_vmaAllocateDeviceMemoryFunction',['../vk__mem__alloc_8h.html#a7e1ed85f7799600b03ad51a77acc21f3',1,'vk_mem_alloc.h']]], + ['pfn_5fvmafreedevicememoryfunction_398',['PFN_vmaFreeDeviceMemoryFunction',['../vk__mem__alloc_8h.html#a154ccaaf53dc2c36378f80f0c4f3679b',1,'vk_mem_alloc.h']]] ]; diff --git a/docs/html/search/typedefs_1.js b/docs/html/search/typedefs_1.js index 33b4cde..ff31250 100644 --- a/docs/html/search/typedefs_1.js +++ b/docs/html/search/typedefs_1.js @@ -1,31 +1,31 @@ var searchData= [ - ['vmaallocationcreateflagbits_401',['VmaAllocationCreateFlagBits',['../vk__mem__alloc_8h.html#a4fceecc301f4064dc808d3cd6c038941',1,'vk_mem_alloc.h']]], - ['vmaallocationcreateflags_402',['VmaAllocationCreateFlags',['../vk__mem__alloc_8h.html#a5225e5e11f8376f6a31a1791f3d6e817',1,'vk_mem_alloc.h']]], - ['vmaallocationcreateinfo_403',['VmaAllocationCreateInfo',['../vk__mem__alloc_8h.html#a3bf110892ea2fb4649fedb68488d026a',1,'vk_mem_alloc.h']]], - ['vmaallocationinfo_404',['VmaAllocationInfo',['../vk__mem__alloc_8h.html#a1cf7774606721026a68aabe3af2e5b50',1,'vk_mem_alloc.h']]], - ['vmaallocatorcreateflagbits_405',['VmaAllocatorCreateFlagBits',['../vk__mem__alloc_8h.html#afd73b95e737ee7e76f827cb5472f559f',1,'vk_mem_alloc.h']]], - ['vmaallocatorcreateflags_406',['VmaAllocatorCreateFlags',['../vk__mem__alloc_8h.html#acfe6863e160722c2c1bbcf7573fddc4d',1,'vk_mem_alloc.h']]], - ['vmaallocatorcreateinfo_407',['VmaAllocatorCreateInfo',['../vk__mem__alloc_8h.html#aad9652301d33759b83e52d4f3605a14a',1,'vk_mem_alloc.h']]], - ['vmaallocatorinfo_408',['VmaAllocatorInfo',['../vk__mem__alloc_8h.html#a1988031b0223fdbd564250fa1edd942c',1,'vk_mem_alloc.h']]], - ['vmabudget_409',['VmaBudget',['../vk__mem__alloc_8h.html#aa078667e71b1ef24e87a6a30d128381d',1,'vk_mem_alloc.h']]], - ['vmadefragmentationflagbits_410',['VmaDefragmentationFlagBits',['../vk__mem__alloc_8h.html#a13415cc0b443353a7b5abda300b833fc',1,'vk_mem_alloc.h']]], - ['vmadefragmentationflags_411',['VmaDefragmentationFlags',['../vk__mem__alloc_8h.html#a88a77cef37e5d3c4fc9eb328885d048d',1,'vk_mem_alloc.h']]], - ['vmadefragmentationinfo_412',['VmaDefragmentationInfo',['../vk__mem__alloc_8h.html#a2bf47f96bf92bed2a49461bd9af3acfa',1,'vk_mem_alloc.h']]], - ['vmadefragmentationinfo2_413',['VmaDefragmentationInfo2',['../vk__mem__alloc_8h.html#ad6daeffaa670ce6d11a203a6224c9937',1,'vk_mem_alloc.h']]], - ['vmadefragmentationpassinfo_414',['VmaDefragmentationPassInfo',['../vk__mem__alloc_8h.html#a72aebd522242d56abea67b4f47f6549e',1,'vk_mem_alloc.h']]], - ['vmadefragmentationpassmoveinfo_415',['VmaDefragmentationPassMoveInfo',['../vk__mem__alloc_8h.html#ad6799e8e2b1527abfc84d33bc44aeaf5',1,'vk_mem_alloc.h']]], - ['vmadefragmentationstats_416',['VmaDefragmentationStats',['../vk__mem__alloc_8h.html#ad94034192259c2e34a4d1c5e27810403',1,'vk_mem_alloc.h']]], - ['vmadevicememorycallbacks_417',['VmaDeviceMemoryCallbacks',['../vk__mem__alloc_8h.html#a77692d3c8770ea8882d573206bd27b2b',1,'vk_mem_alloc.h']]], - ['vmamemoryusage_418',['VmaMemoryUsage',['../vk__mem__alloc_8h.html#a806e8499dde802e59eb72a1dc811c35f',1,'vk_mem_alloc.h']]], - ['vmapoolcreateflagbits_419',['VmaPoolCreateFlagBits',['../vk__mem__alloc_8h.html#a4d4f2efc2509157a9e4ecd4fd7942303',1,'vk_mem_alloc.h']]], - ['vmapoolcreateflags_420',['VmaPoolCreateFlags',['../vk__mem__alloc_8h.html#a2770e325ea42e087c1b91fdf46d0292a',1,'vk_mem_alloc.h']]], - ['vmapoolcreateinfo_421',['VmaPoolCreateInfo',['../vk__mem__alloc_8h.html#a1017aa83489c0eee8d2163d2bf253f67',1,'vk_mem_alloc.h']]], - ['vmapoolstats_422',['VmaPoolStats',['../vk__mem__alloc_8h.html#a4759a2d9f99c19ba7627553c847132f1',1,'vk_mem_alloc.h']]], - ['vmarecordflagbits_423',['VmaRecordFlagBits',['../vk__mem__alloc_8h.html#acd24d5eb58abff7e1f43cb32a1ba1413',1,'vk_mem_alloc.h']]], - ['vmarecordflags_424',['VmaRecordFlags',['../vk__mem__alloc_8h.html#af3929a1a4547c592fc0b0e55ef452828',1,'vk_mem_alloc.h']]], - ['vmarecordsettings_425',['VmaRecordSettings',['../vk__mem__alloc_8h.html#a16e21c877101493fce582664cd8754fc',1,'vk_mem_alloc.h']]], - ['vmastatinfo_426',['VmaStatInfo',['../vk__mem__alloc_8h.html#aec5b57e29c97b5d69c6d5654d60df878',1,'vk_mem_alloc.h']]], - ['vmastats_427',['VmaStats',['../vk__mem__alloc_8h.html#a21813b2efdf3836767a9058cd8a94034',1,'vk_mem_alloc.h']]], - ['vmavulkanfunctions_428',['VmaVulkanFunctions',['../vk__mem__alloc_8h.html#abb0a8e3b5040d847571cca6c7f9a8074',1,'vk_mem_alloc.h']]] + ['vmaallocationcreateflagbits_399',['VmaAllocationCreateFlagBits',['../vk__mem__alloc_8h.html#a4fceecc301f4064dc808d3cd6c038941',1,'vk_mem_alloc.h']]], + ['vmaallocationcreateflags_400',['VmaAllocationCreateFlags',['../vk__mem__alloc_8h.html#a5225e5e11f8376f6a31a1791f3d6e817',1,'vk_mem_alloc.h']]], + ['vmaallocationcreateinfo_401',['VmaAllocationCreateInfo',['../vk__mem__alloc_8h.html#a3bf110892ea2fb4649fedb68488d026a',1,'vk_mem_alloc.h']]], + ['vmaallocationinfo_402',['VmaAllocationInfo',['../vk__mem__alloc_8h.html#a1cf7774606721026a68aabe3af2e5b50',1,'vk_mem_alloc.h']]], + ['vmaallocatorcreateflagbits_403',['VmaAllocatorCreateFlagBits',['../vk__mem__alloc_8h.html#afd73b95e737ee7e76f827cb5472f559f',1,'vk_mem_alloc.h']]], + ['vmaallocatorcreateflags_404',['VmaAllocatorCreateFlags',['../vk__mem__alloc_8h.html#acfe6863e160722c2c1bbcf7573fddc4d',1,'vk_mem_alloc.h']]], + ['vmaallocatorcreateinfo_405',['VmaAllocatorCreateInfo',['../vk__mem__alloc_8h.html#aad9652301d33759b83e52d4f3605a14a',1,'vk_mem_alloc.h']]], + ['vmaallocatorinfo_406',['VmaAllocatorInfo',['../vk__mem__alloc_8h.html#a1988031b0223fdbd564250fa1edd942c',1,'vk_mem_alloc.h']]], + ['vmabudget_407',['VmaBudget',['../vk__mem__alloc_8h.html#aa078667e71b1ef24e87a6a30d128381d',1,'vk_mem_alloc.h']]], + ['vmadefragmentationflagbits_408',['VmaDefragmentationFlagBits',['../vk__mem__alloc_8h.html#a13415cc0b443353a7b5abda300b833fc',1,'vk_mem_alloc.h']]], + ['vmadefragmentationflags_409',['VmaDefragmentationFlags',['../vk__mem__alloc_8h.html#a88a77cef37e5d3c4fc9eb328885d048d',1,'vk_mem_alloc.h']]], + ['vmadefragmentationinfo_410',['VmaDefragmentationInfo',['../vk__mem__alloc_8h.html#a2bf47f96bf92bed2a49461bd9af3acfa',1,'vk_mem_alloc.h']]], + ['vmadefragmentationinfo2_411',['VmaDefragmentationInfo2',['../vk__mem__alloc_8h.html#ad6daeffaa670ce6d11a203a6224c9937',1,'vk_mem_alloc.h']]], + ['vmadefragmentationpassinfo_412',['VmaDefragmentationPassInfo',['../vk__mem__alloc_8h.html#a72aebd522242d56abea67b4f47f6549e',1,'vk_mem_alloc.h']]], + ['vmadefragmentationpassmoveinfo_413',['VmaDefragmentationPassMoveInfo',['../vk__mem__alloc_8h.html#ad6799e8e2b1527abfc84d33bc44aeaf5',1,'vk_mem_alloc.h']]], + ['vmadefragmentationstats_414',['VmaDefragmentationStats',['../vk__mem__alloc_8h.html#ad94034192259c2e34a4d1c5e27810403',1,'vk_mem_alloc.h']]], + ['vmadevicememorycallbacks_415',['VmaDeviceMemoryCallbacks',['../vk__mem__alloc_8h.html#a77692d3c8770ea8882d573206bd27b2b',1,'vk_mem_alloc.h']]], + ['vmamemoryusage_416',['VmaMemoryUsage',['../vk__mem__alloc_8h.html#a806e8499dde802e59eb72a1dc811c35f',1,'vk_mem_alloc.h']]], + ['vmapoolcreateflagbits_417',['VmaPoolCreateFlagBits',['../vk__mem__alloc_8h.html#a4d4f2efc2509157a9e4ecd4fd7942303',1,'vk_mem_alloc.h']]], + ['vmapoolcreateflags_418',['VmaPoolCreateFlags',['../vk__mem__alloc_8h.html#a2770e325ea42e087c1b91fdf46d0292a',1,'vk_mem_alloc.h']]], + ['vmapoolcreateinfo_419',['VmaPoolCreateInfo',['../vk__mem__alloc_8h.html#a1017aa83489c0eee8d2163d2bf253f67',1,'vk_mem_alloc.h']]], + ['vmapoolstats_420',['VmaPoolStats',['../vk__mem__alloc_8h.html#a4759a2d9f99c19ba7627553c847132f1',1,'vk_mem_alloc.h']]], + ['vmarecordflagbits_421',['VmaRecordFlagBits',['../vk__mem__alloc_8h.html#acd24d5eb58abff7e1f43cb32a1ba1413',1,'vk_mem_alloc.h']]], + ['vmarecordflags_422',['VmaRecordFlags',['../vk__mem__alloc_8h.html#af3929a1a4547c592fc0b0e55ef452828',1,'vk_mem_alloc.h']]], + ['vmarecordsettings_423',['VmaRecordSettings',['../vk__mem__alloc_8h.html#a16e21c877101493fce582664cd8754fc',1,'vk_mem_alloc.h']]], + ['vmastatinfo_424',['VmaStatInfo',['../vk__mem__alloc_8h.html#aec5b57e29c97b5d69c6d5654d60df878',1,'vk_mem_alloc.h']]], + ['vmastats_425',['VmaStats',['../vk__mem__alloc_8h.html#a21813b2efdf3836767a9058cd8a94034',1,'vk_mem_alloc.h']]], + ['vmavulkanfunctions_426',['VmaVulkanFunctions',['../vk__mem__alloc_8h.html#abb0a8e3b5040d847571cca6c7f9a8074',1,'vk_mem_alloc.h']]] ]; diff --git a/docs/html/search/variables_0.js b/docs/html/search/variables_0.js index b48c4e6..b736596 100644 --- a/docs/html/search/variables_0.js +++ b/docs/html/search/variables_0.js @@ -1,10 +1,10 @@ var searchData= [ - ['allocation_315',['allocation',['../struct_vma_defragmentation_pass_move_info.html#ae885c861c2dd8d622e6c19e281d035cc',1,'VmaDefragmentationPassMoveInfo']]], - ['allocationbytes_316',['allocationBytes',['../struct_vma_budget.html#a7e2a6583ebd63e194951c542563804d8',1,'VmaBudget']]], - ['allocationcount_317',['allocationCount',['../struct_vma_stat_info.html#a537741e4d5cdddc1c0ab95ec650afaff',1,'VmaStatInfo::allocationCount()'],['../struct_vma_pool_stats.html#ad1924eb54fffa45e9e0e65670c8fe5eb',1,'VmaPoolStats::allocationCount()'],['../struct_vma_defragmentation_info2.html#a3cf86ab32c1da779b4923d301a3056ba',1,'VmaDefragmentationInfo2::allocationCount()']]], - ['allocationsizeavg_318',['allocationSizeAvg',['../struct_vma_stat_info.html#a1081a039964e566c672e7a2347f9e599',1,'VmaStatInfo']]], - ['allocationsizemax_319',['allocationSizeMax',['../struct_vma_stat_info.html#a17e9733a5ecd76287d4db6e66f71f50c',1,'VmaStatInfo']]], - ['allocationsizemin_320',['allocationSizeMin',['../struct_vma_stat_info.html#ade8b40bd3139c04aabd2fc538a356fea',1,'VmaStatInfo']]], - ['allocationsmoved_321',['allocationsMoved',['../struct_vma_defragmentation_stats.html#aefeabf130022008eadd75999478af3f9',1,'VmaDefragmentationStats']]] + ['allocation_313',['allocation',['../struct_vma_defragmentation_pass_move_info.html#ae885c861c2dd8d622e6c19e281d035cc',1,'VmaDefragmentationPassMoveInfo']]], + ['allocationbytes_314',['allocationBytes',['../struct_vma_budget.html#a7e2a6583ebd63e194951c542563804d8',1,'VmaBudget']]], + ['allocationcount_315',['allocationCount',['../struct_vma_stat_info.html#a537741e4d5cdddc1c0ab95ec650afaff',1,'VmaStatInfo::allocationCount()'],['../struct_vma_pool_stats.html#ad1924eb54fffa45e9e0e65670c8fe5eb',1,'VmaPoolStats::allocationCount()'],['../struct_vma_defragmentation_info2.html#a3cf86ab32c1da779b4923d301a3056ba',1,'VmaDefragmentationInfo2::allocationCount()']]], + ['allocationsizeavg_316',['allocationSizeAvg',['../struct_vma_stat_info.html#a1081a039964e566c672e7a2347f9e599',1,'VmaStatInfo']]], + ['allocationsizemax_317',['allocationSizeMax',['../struct_vma_stat_info.html#a17e9733a5ecd76287d4db6e66f71f50c',1,'VmaStatInfo']]], + ['allocationsizemin_318',['allocationSizeMin',['../struct_vma_stat_info.html#ade8b40bd3139c04aabd2fc538a356fea',1,'VmaStatInfo']]], + ['allocationsmoved_319',['allocationsMoved',['../struct_vma_defragmentation_stats.html#aefeabf130022008eadd75999478af3f9',1,'VmaDefragmentationStats']]] ]; diff --git a/docs/html/search/variables_1.js b/docs/html/search/variables_1.js index 8466fe9..71f3c5d 100644 --- a/docs/html/search/variables_1.js +++ b/docs/html/search/variables_1.js @@ -1,9 +1,9 @@ var searchData= [ - ['blockbytes_322',['blockBytes',['../struct_vma_budget.html#a58b492901baab685f466199124e514a0',1,'VmaBudget']]], - ['blockcount_323',['blockCount',['../struct_vma_stat_info.html#abc4bb7cd611900778464c56e50c970a4',1,'VmaStatInfo::blockCount()'],['../struct_vma_pool_stats.html#aa0b5cb45cef6f18571cefb03b9a230e7',1,'VmaPoolStats::blockCount()']]], - ['blocksize_324',['blockSize',['../struct_vma_pool_create_info.html#aa4265160536cdb9be821b7686c16c676',1,'VmaPoolCreateInfo']]], - ['budget_325',['budget',['../struct_vma_budget.html#ab82e1d1754c2d210d0bdf90220bc6cdd',1,'VmaBudget']]], - ['bytesfreed_326',['bytesFreed',['../struct_vma_defragmentation_stats.html#ab0cb9ac0dbc106c77e384ea676422f28',1,'VmaDefragmentationStats']]], - ['bytesmoved_327',['bytesMoved',['../struct_vma_defragmentation_stats.html#a36f9d5df2a10ba2a36b16e126d60572d',1,'VmaDefragmentationStats']]] + ['blockbytes_320',['blockBytes',['../struct_vma_budget.html#a58b492901baab685f466199124e514a0',1,'VmaBudget']]], + ['blockcount_321',['blockCount',['../struct_vma_stat_info.html#abc4bb7cd611900778464c56e50c970a4',1,'VmaStatInfo::blockCount()'],['../struct_vma_pool_stats.html#aa0b5cb45cef6f18571cefb03b9a230e7',1,'VmaPoolStats::blockCount()']]], + ['blocksize_322',['blockSize',['../struct_vma_pool_create_info.html#aa4265160536cdb9be821b7686c16c676',1,'VmaPoolCreateInfo']]], + ['budget_323',['budget',['../struct_vma_budget.html#ab82e1d1754c2d210d0bdf90220bc6cdd',1,'VmaBudget']]], + ['bytesfreed_324',['bytesFreed',['../struct_vma_defragmentation_stats.html#ab0cb9ac0dbc106c77e384ea676422f28',1,'VmaDefragmentationStats']]], + ['bytesmoved_325',['bytesMoved',['../struct_vma_defragmentation_stats.html#a36f9d5df2a10ba2a36b16e126d60572d',1,'VmaDefragmentationStats']]] ]; diff --git a/docs/html/search/variables_2.js b/docs/html/search/variables_2.js index 26c79ea..edcfe09 100644 --- a/docs/html/search/variables_2.js +++ b/docs/html/search/variables_2.js @@ -1,4 +1,4 @@ var searchData= [ - ['commandbuffer_328',['commandBuffer',['../struct_vma_defragmentation_info2.html#a7f71f39590c5316771493d2333f9c1bd',1,'VmaDefragmentationInfo2']]] + ['commandbuffer_326',['commandBuffer',['../struct_vma_defragmentation_info2.html#a7f71f39590c5316771493d2333f9c1bd',1,'VmaDefragmentationInfo2']]] ]; diff --git a/docs/html/search/variables_3.js b/docs/html/search/variables_3.js index 7235a7e..65200bb 100644 --- a/docs/html/search/variables_3.js +++ b/docs/html/search/variables_3.js @@ -1,6 +1,6 @@ var searchData= [ - ['device_329',['device',['../struct_vma_allocator_create_info.html#ad924ddd77b04039c88d0c09b0ffcd500',1,'VmaAllocatorCreateInfo::device()'],['../struct_vma_allocator_info.html#a012b4c485bf3b0ea8921352c5ee0c357',1,'VmaAllocatorInfo::device()']]], - ['devicememory_330',['deviceMemory',['../struct_vma_allocation_info.html#ae0bfb7dfdf79a76ffefc9a94677a2f67',1,'VmaAllocationInfo']]], - ['devicememoryblocksfreed_331',['deviceMemoryBlocksFreed',['../struct_vma_defragmentation_stats.html#a0113f1877904a5d1ee8f409216ff276b',1,'VmaDefragmentationStats']]] + ['device_327',['device',['../struct_vma_allocator_create_info.html#ad924ddd77b04039c88d0c09b0ffcd500',1,'VmaAllocatorCreateInfo::device()'],['../struct_vma_allocator_info.html#a012b4c485bf3b0ea8921352c5ee0c357',1,'VmaAllocatorInfo::device()']]], + ['devicememory_328',['deviceMemory',['../struct_vma_allocation_info.html#ae0bfb7dfdf79a76ffefc9a94677a2f67',1,'VmaAllocationInfo']]], + ['devicememoryblocksfreed_329',['deviceMemoryBlocksFreed',['../struct_vma_defragmentation_stats.html#a0113f1877904a5d1ee8f409216ff276b',1,'VmaDefragmentationStats']]] ]; diff --git a/docs/html/search/variables_4.js b/docs/html/search/variables_4.js index 6688225..31b9769 100644 --- a/docs/html/search/variables_4.js +++ b/docs/html/search/variables_4.js @@ -1,5 +1,5 @@ var searchData= [ - ['flags_332',['flags',['../struct_vma_record_settings.html#ad8fdcc92119ae7a8c08c1a564c01d63a',1,'VmaRecordSettings::flags()'],['../struct_vma_allocator_create_info.html#a392ea2ecbaff93f91a7c49f735ad4346',1,'VmaAllocatorCreateInfo::flags()'],['../struct_vma_allocation_create_info.html#add09658ac14fe290ace25470ddd6d41b',1,'VmaAllocationCreateInfo::flags()'],['../struct_vma_pool_create_info.html#a8405139f63d078340ae74513a59f5446',1,'VmaPoolCreateInfo::flags()'],['../struct_vma_defragmentation_info2.html#a53e844ee5633e229cf6daf14b2d9fff9',1,'VmaDefragmentationInfo2::flags()']]], - ['frameinusecount_333',['frameInUseCount',['../struct_vma_allocator_create_info.html#a21ea188dd212b8171cb9ecbed4a2a3a7',1,'VmaAllocatorCreateInfo::frameInUseCount()'],['../struct_vma_pool_create_info.html#a9437e43ffbb644dbbf7fc4e50cfad6aa',1,'VmaPoolCreateInfo::frameInUseCount()']]] + ['flags_330',['flags',['../struct_vma_record_settings.html#ad8fdcc92119ae7a8c08c1a564c01d63a',1,'VmaRecordSettings::flags()'],['../struct_vma_allocator_create_info.html#a392ea2ecbaff93f91a7c49f735ad4346',1,'VmaAllocatorCreateInfo::flags()'],['../struct_vma_allocation_create_info.html#add09658ac14fe290ace25470ddd6d41b',1,'VmaAllocationCreateInfo::flags()'],['../struct_vma_pool_create_info.html#a8405139f63d078340ae74513a59f5446',1,'VmaPoolCreateInfo::flags()'],['../struct_vma_defragmentation_info2.html#a53e844ee5633e229cf6daf14b2d9fff9',1,'VmaDefragmentationInfo2::flags()']]], + ['frameinusecount_331',['frameInUseCount',['../struct_vma_allocator_create_info.html#a21ea188dd212b8171cb9ecbed4a2a3a7',1,'VmaAllocatorCreateInfo::frameInUseCount()'],['../struct_vma_pool_create_info.html#a9437e43ffbb644dbbf7fc4e50cfad6aa',1,'VmaPoolCreateInfo::frameInUseCount()']]] ]; diff --git a/docs/html/search/variables_5.js b/docs/html/search/variables_5.js index 017812a..0aad120 100644 --- a/docs/html/search/variables_5.js +++ b/docs/html/search/variables_5.js @@ -1,4 +1,4 @@ var searchData= [ - ['instance_334',['instance',['../struct_vma_allocator_create_info.html#a70dd42e29b1df1d1b9b61532ae0b370b',1,'VmaAllocatorCreateInfo::instance()'],['../struct_vma_allocator_info.html#a2ed6a4d2d3fea039d66a13f15d0ce5fe',1,'VmaAllocatorInfo::instance()']]] + ['instance_332',['instance',['../struct_vma_allocator_create_info.html#a70dd42e29b1df1d1b9b61532ae0b370b',1,'VmaAllocatorCreateInfo::instance()'],['../struct_vma_allocator_info.html#a2ed6a4d2d3fea039d66a13f15d0ce5fe',1,'VmaAllocatorInfo::instance()']]] ]; diff --git a/docs/html/search/variables_6.js b/docs/html/search/variables_6.js index 28021d6..168f828 100644 --- a/docs/html/search/variables_6.js +++ b/docs/html/search/variables_6.js @@ -1,17 +1,17 @@ var searchData= [ - ['maxallocationstomove_335',['maxAllocationsToMove',['../struct_vma_defragmentation_info.html#aa7c7304e13c71f604c907196c4e28fbc',1,'VmaDefragmentationInfo']]], - ['maxblockcount_336',['maxBlockCount',['../struct_vma_pool_create_info.html#ae41142f2834fcdc82baa4883c187b75c',1,'VmaPoolCreateInfo']]], - ['maxbytestomove_337',['maxBytesToMove',['../struct_vma_defragmentation_info.html#acb311c940a777270e67e1b81c5ab6a1d',1,'VmaDefragmentationInfo']]], - ['maxcpuallocationstomove_338',['maxCpuAllocationsToMove',['../struct_vma_defragmentation_info2.html#a94c2c7223d52878445a8cccce396b671',1,'VmaDefragmentationInfo2']]], - ['maxcpubytestomove_339',['maxCpuBytesToMove',['../struct_vma_defragmentation_info2.html#af78e1ea40c22d85137b65f6b384a4d0a',1,'VmaDefragmentationInfo2']]], - ['maxgpuallocationstomove_340',['maxGpuAllocationsToMove',['../struct_vma_defragmentation_info2.html#a40d53d33e71ba0b66f844ed63c05a3f6',1,'VmaDefragmentationInfo2']]], - ['maxgpubytestomove_341',['maxGpuBytesToMove',['../struct_vma_defragmentation_info2.html#a4ddbc898d0afe1518f863a3763628f08',1,'VmaDefragmentationInfo2']]], - ['memory_342',['memory',['../struct_vma_defragmentation_pass_move_info.html#a06eb0c8690aa0d3478a036753492e769',1,'VmaDefragmentationPassMoveInfo']]], - ['memoryheap_343',['memoryHeap',['../struct_vma_stats.html#a0e6611508c29a187f0fd14ff1a0329c0',1,'VmaStats']]], - ['memorytype_344',['memoryType',['../struct_vma_stats.html#a13e3caf754be79352c42408756309331',1,'VmaStats::memoryType()'],['../struct_vma_allocation_info.html#a7f6b0aa58c135e488e6b40a388dad9d5',1,'VmaAllocationInfo::memoryType()']]], - ['memorytypebits_345',['memoryTypeBits',['../struct_vma_allocation_create_info.html#a3bf940c0271d85d6ba32a4d820075055',1,'VmaAllocationCreateInfo']]], - ['memorytypeindex_346',['memoryTypeIndex',['../struct_vma_pool_create_info.html#a596fa76b685d3f1f688f84a709a5b319',1,'VmaPoolCreateInfo']]], - ['minblockcount_347',['minBlockCount',['../struct_vma_pool_create_info.html#ad8006fb803185c0a699d30f3e9a865ae',1,'VmaPoolCreateInfo']]], - ['movecount_348',['moveCount',['../struct_vma_defragmentation_pass_info.html#ac1086e657ba995f8d1f4e49b83dcfb6c',1,'VmaDefragmentationPassInfo']]] + ['maxallocationstomove_333',['maxAllocationsToMove',['../struct_vma_defragmentation_info.html#aa7c7304e13c71f604c907196c4e28fbc',1,'VmaDefragmentationInfo']]], + ['maxblockcount_334',['maxBlockCount',['../struct_vma_pool_create_info.html#ae41142f2834fcdc82baa4883c187b75c',1,'VmaPoolCreateInfo']]], + ['maxbytestomove_335',['maxBytesToMove',['../struct_vma_defragmentation_info.html#acb311c940a777270e67e1b81c5ab6a1d',1,'VmaDefragmentationInfo']]], + ['maxcpuallocationstomove_336',['maxCpuAllocationsToMove',['../struct_vma_defragmentation_info2.html#a94c2c7223d52878445a8cccce396b671',1,'VmaDefragmentationInfo2']]], + ['maxcpubytestomove_337',['maxCpuBytesToMove',['../struct_vma_defragmentation_info2.html#af78e1ea40c22d85137b65f6b384a4d0a',1,'VmaDefragmentationInfo2']]], + ['maxgpuallocationstomove_338',['maxGpuAllocationsToMove',['../struct_vma_defragmentation_info2.html#a40d53d33e71ba0b66f844ed63c05a3f6',1,'VmaDefragmentationInfo2']]], + ['maxgpubytestomove_339',['maxGpuBytesToMove',['../struct_vma_defragmentation_info2.html#a4ddbc898d0afe1518f863a3763628f08',1,'VmaDefragmentationInfo2']]], + ['memory_340',['memory',['../struct_vma_defragmentation_pass_move_info.html#a06eb0c8690aa0d3478a036753492e769',1,'VmaDefragmentationPassMoveInfo']]], + ['memoryheap_341',['memoryHeap',['../struct_vma_stats.html#a0e6611508c29a187f0fd14ff1a0329c0',1,'VmaStats']]], + ['memorytype_342',['memoryType',['../struct_vma_stats.html#a13e3caf754be79352c42408756309331',1,'VmaStats::memoryType()'],['../struct_vma_allocation_info.html#a7f6b0aa58c135e488e6b40a388dad9d5',1,'VmaAllocationInfo::memoryType()']]], + ['memorytypebits_343',['memoryTypeBits',['../struct_vma_allocation_create_info.html#a3bf940c0271d85d6ba32a4d820075055',1,'VmaAllocationCreateInfo']]], + ['memorytypeindex_344',['memoryTypeIndex',['../struct_vma_pool_create_info.html#a596fa76b685d3f1f688f84a709a5b319',1,'VmaPoolCreateInfo']]], + ['minblockcount_345',['minBlockCount',['../struct_vma_pool_create_info.html#ad8006fb803185c0a699d30f3e9a865ae',1,'VmaPoolCreateInfo']]], + ['movecount_346',['moveCount',['../struct_vma_defragmentation_pass_info.html#ac1086e657ba995f8d1f4e49b83dcfb6c',1,'VmaDefragmentationPassInfo']]] ]; diff --git a/docs/html/search/variables_7.js b/docs/html/search/variables_7.js index 968b3a7..e68edf1 100644 --- a/docs/html/search/variables_7.js +++ b/docs/html/search/variables_7.js @@ -1,4 +1,4 @@ var searchData= [ - ['offset_349',['offset',['../struct_vma_allocation_info.html#a4a3c732388dbdc7a23f9365b00825268',1,'VmaAllocationInfo::offset()'],['../struct_vma_defragmentation_pass_move_info.html#a8ab4508bc03625b0653c880576be96c6',1,'VmaDefragmentationPassMoveInfo::offset()']]] + ['offset_347',['offset',['../struct_vma_allocation_info.html#a4a3c732388dbdc7a23f9365b00825268',1,'VmaAllocationInfo::offset()'],['../struct_vma_defragmentation_pass_move_info.html#a8ab4508bc03625b0653c880576be96c6',1,'VmaDefragmentationPassMoveInfo::offset()']]] ]; diff --git a/docs/html/search/variables_8.js b/docs/html/search/variables_8.js index 2493d69..22a6742 100644 --- a/docs/html/search/variables_8.js +++ b/docs/html/search/variables_8.js @@ -1,23 +1,23 @@ var searchData= [ - ['pallocationcallbacks_350',['pAllocationCallbacks',['../struct_vma_allocator_create_info.html#a6e409087e3be55400d0e4ccbe43c608d',1,'VmaAllocatorCreateInfo']]], - ['pallocations_351',['pAllocations',['../struct_vma_defragmentation_info2.html#ab6d288f29d028156cf73542d630a2e32',1,'VmaDefragmentationInfo2']]], - ['pallocationschanged_352',['pAllocationsChanged',['../struct_vma_defragmentation_info2.html#a76d51a644dc7f5405d0cdd0025ecd0cc',1,'VmaDefragmentationInfo2']]], - ['pdevicememorycallbacks_353',['pDeviceMemoryCallbacks',['../struct_vma_allocator_create_info.html#af1380969b5e1ea4c3184a877892d260e',1,'VmaAllocatorCreateInfo']]], - ['pfilepath_354',['pFilePath',['../struct_vma_record_settings.html#a6cb1fdbf6bcb610b68f2010dd629e89d',1,'VmaRecordSettings']]], - ['pfnallocate_355',['pfnAllocate',['../struct_vma_device_memory_callbacks.html#a4f17f7b255101e733b44d5633aceabfb',1,'VmaDeviceMemoryCallbacks']]], - ['pfnfree_356',['pfnFree',['../struct_vma_device_memory_callbacks.html#abe8a3328bbc916f6f712fdb6b299444c',1,'VmaDeviceMemoryCallbacks']]], - ['pheapsizelimit_357',['pHeapSizeLimit',['../struct_vma_allocator_create_info.html#a31c192aa6cbffa33279f6d9f0c47c44b',1,'VmaAllocatorCreateInfo']]], - ['physicaldevice_358',['physicalDevice',['../struct_vma_allocator_create_info.html#a08230f04ae6ccf8a78150a9e829a7156',1,'VmaAllocatorCreateInfo::physicalDevice()'],['../struct_vma_allocator_info.html#aba2b703f96e51d567717e1fb2935b47a',1,'VmaAllocatorInfo::physicalDevice()']]], - ['pmappeddata_359',['pMappedData',['../struct_vma_allocation_info.html#a5eeffbe2d2f30f53370ff14aefbadbe2',1,'VmaAllocationInfo']]], - ['pmoves_360',['pMoves',['../struct_vma_defragmentation_pass_info.html#acbd42d4a3357999da130a95cd99a3792',1,'VmaDefragmentationPassInfo']]], - ['pool_361',['pool',['../struct_vma_allocation_create_info.html#a6272c0555cfd1fe28bff1afeb6190150',1,'VmaAllocationCreateInfo']]], - ['poolcount_362',['poolCount',['../struct_vma_defragmentation_info2.html#a7e70aa2a1081d849dcc7829b19d3ec9d',1,'VmaDefragmentationInfo2']]], - ['ppools_363',['pPools',['../struct_vma_defragmentation_info2.html#a3c9c6aa5c97d5670f8e362b3a6f3029b',1,'VmaDefragmentationInfo2']]], - ['precordsettings_364',['pRecordSettings',['../struct_vma_allocator_create_info.html#ace2aa4877b16a42b0b7673d4e26000ee',1,'VmaAllocatorCreateInfo']]], - ['preferredflags_365',['preferredFlags',['../struct_vma_allocation_create_info.html#a7fe8d81a1ad10b2a2faacacee5b15d6d',1,'VmaAllocationCreateInfo']]], - ['preferredlargeheapblocksize_366',['preferredLargeHeapBlockSize',['../struct_vma_allocator_create_info.html#a8e4714298e3121cdd8b214a1ae7a637a',1,'VmaAllocatorCreateInfo']]], - ['priority_367',['priority',['../struct_vma_allocation_create_info.html#a983d39e1a2e63649d78a960aa2fdd0f7',1,'VmaAllocationCreateInfo::priority()'],['../struct_vma_pool_create_info.html#a16e686c688f6725f119ebf6e24ab5274',1,'VmaPoolCreateInfo::priority()']]], - ['puserdata_368',['pUserData',['../struct_vma_device_memory_callbacks.html#a24052de0937ddd54015a2df0363903c6',1,'VmaDeviceMemoryCallbacks::pUserData()'],['../struct_vma_allocation_create_info.html#a8259e85c272683434f4abb4ddddffe19',1,'VmaAllocationCreateInfo::pUserData()'],['../struct_vma_allocation_info.html#adc507656149c04de7ed95d0042ba2a13',1,'VmaAllocationInfo::pUserData()']]], - ['pvulkanfunctions_369',['pVulkanFunctions',['../struct_vma_allocator_create_info.html#a3dc197be3227da7338b1643f70db36bd',1,'VmaAllocatorCreateInfo']]] + ['pallocationcallbacks_348',['pAllocationCallbacks',['../struct_vma_allocator_create_info.html#a6e409087e3be55400d0e4ccbe43c608d',1,'VmaAllocatorCreateInfo']]], + ['pallocations_349',['pAllocations',['../struct_vma_defragmentation_info2.html#ab6d288f29d028156cf73542d630a2e32',1,'VmaDefragmentationInfo2']]], + ['pallocationschanged_350',['pAllocationsChanged',['../struct_vma_defragmentation_info2.html#a76d51a644dc7f5405d0cdd0025ecd0cc',1,'VmaDefragmentationInfo2']]], + ['pdevicememorycallbacks_351',['pDeviceMemoryCallbacks',['../struct_vma_allocator_create_info.html#af1380969b5e1ea4c3184a877892d260e',1,'VmaAllocatorCreateInfo']]], + ['pfilepath_352',['pFilePath',['../struct_vma_record_settings.html#a6cb1fdbf6bcb610b68f2010dd629e89d',1,'VmaRecordSettings']]], + ['pfnallocate_353',['pfnAllocate',['../struct_vma_device_memory_callbacks.html#a4f17f7b255101e733b44d5633aceabfb',1,'VmaDeviceMemoryCallbacks']]], + ['pfnfree_354',['pfnFree',['../struct_vma_device_memory_callbacks.html#abe8a3328bbc916f6f712fdb6b299444c',1,'VmaDeviceMemoryCallbacks']]], + ['pheapsizelimit_355',['pHeapSizeLimit',['../struct_vma_allocator_create_info.html#a31c192aa6cbffa33279f6d9f0c47c44b',1,'VmaAllocatorCreateInfo']]], + ['physicaldevice_356',['physicalDevice',['../struct_vma_allocator_create_info.html#a08230f04ae6ccf8a78150a9e829a7156',1,'VmaAllocatorCreateInfo::physicalDevice()'],['../struct_vma_allocator_info.html#aba2b703f96e51d567717e1fb2935b47a',1,'VmaAllocatorInfo::physicalDevice()']]], + ['pmappeddata_357',['pMappedData',['../struct_vma_allocation_info.html#a5eeffbe2d2f30f53370ff14aefbadbe2',1,'VmaAllocationInfo']]], + ['pmoves_358',['pMoves',['../struct_vma_defragmentation_pass_info.html#acbd42d4a3357999da130a95cd99a3792',1,'VmaDefragmentationPassInfo']]], + ['pool_359',['pool',['../struct_vma_allocation_create_info.html#a6272c0555cfd1fe28bff1afeb6190150',1,'VmaAllocationCreateInfo']]], + ['poolcount_360',['poolCount',['../struct_vma_defragmentation_info2.html#a7e70aa2a1081d849dcc7829b19d3ec9d',1,'VmaDefragmentationInfo2']]], + ['ppools_361',['pPools',['../struct_vma_defragmentation_info2.html#a3c9c6aa5c97d5670f8e362b3a6f3029b',1,'VmaDefragmentationInfo2']]], + ['precordsettings_362',['pRecordSettings',['../struct_vma_allocator_create_info.html#ace2aa4877b16a42b0b7673d4e26000ee',1,'VmaAllocatorCreateInfo']]], + ['preferredflags_363',['preferredFlags',['../struct_vma_allocation_create_info.html#a7fe8d81a1ad10b2a2faacacee5b15d6d',1,'VmaAllocationCreateInfo']]], + ['preferredlargeheapblocksize_364',['preferredLargeHeapBlockSize',['../struct_vma_allocator_create_info.html#a8e4714298e3121cdd8b214a1ae7a637a',1,'VmaAllocatorCreateInfo']]], + ['priority_365',['priority',['../struct_vma_allocation_create_info.html#a983d39e1a2e63649d78a960aa2fdd0f7',1,'VmaAllocationCreateInfo::priority()'],['../struct_vma_pool_create_info.html#a16e686c688f6725f119ebf6e24ab5274',1,'VmaPoolCreateInfo::priority()']]], + ['puserdata_366',['pUserData',['../struct_vma_device_memory_callbacks.html#a24052de0937ddd54015a2df0363903c6',1,'VmaDeviceMemoryCallbacks::pUserData()'],['../struct_vma_allocation_create_info.html#a8259e85c272683434f4abb4ddddffe19',1,'VmaAllocationCreateInfo::pUserData()'],['../struct_vma_allocation_info.html#adc507656149c04de7ed95d0042ba2a13',1,'VmaAllocationInfo::pUserData()']]], + ['pvulkanfunctions_367',['pVulkanFunctions',['../struct_vma_allocator_create_info.html#a3dc197be3227da7338b1643f70db36bd',1,'VmaAllocatorCreateInfo']]] ]; diff --git a/docs/html/search/variables_9.js b/docs/html/search/variables_9.js index 839c821..18f4728 100644 --- a/docs/html/search/variables_9.js +++ b/docs/html/search/variables_9.js @@ -1,4 +1,4 @@ var searchData= [ - ['requiredflags_370',['requiredFlags',['../struct_vma_allocation_create_info.html#a9166390303ff42d783305bc31c2b6b90',1,'VmaAllocationCreateInfo']]] + ['requiredflags_368',['requiredFlags',['../struct_vma_allocation_create_info.html#a9166390303ff42d783305bc31c2b6b90',1,'VmaAllocationCreateInfo']]] ]; diff --git a/docs/html/search/variables_a.js b/docs/html/search/variables_a.js index ce02717..d9db73f 100644 --- a/docs/html/search/variables_a.js +++ b/docs/html/search/variables_a.js @@ -1,4 +1,4 @@ var searchData= [ - ['size_371',['size',['../struct_vma_pool_stats.html#a326807b2de2b0931cee4ed9a5f2e420c',1,'VmaPoolStats::size()'],['../struct_vma_allocation_info.html#aac76d113a6a5ccbb09fea00fb25fd18f',1,'VmaAllocationInfo::size()']]] + ['size_369',['size',['../struct_vma_pool_stats.html#a326807b2de2b0931cee4ed9a5f2e420c',1,'VmaPoolStats::size()'],['../struct_vma_allocation_info.html#aac76d113a6a5ccbb09fea00fb25fd18f',1,'VmaAllocationInfo::size()']]] ]; diff --git a/docs/html/search/variables_b.js b/docs/html/search/variables_b.js index a4a74ee..2132c6b 100644 --- a/docs/html/search/variables_b.js +++ b/docs/html/search/variables_b.js @@ -1,4 +1,4 @@ var searchData= [ - ['total_372',['total',['../struct_vma_stats.html#a2e8f5b3353f2fefef3c27f29e245a1f9',1,'VmaStats']]] + ['total_370',['total',['../struct_vma_stats.html#a2e8f5b3353f2fefef3c27f29e245a1f9',1,'VmaStats']]] ]; diff --git a/docs/html/search/variables_c.js b/docs/html/search/variables_c.js index c39f789..9a7df57 100644 --- a/docs/html/search/variables_c.js +++ b/docs/html/search/variables_c.js @@ -1,11 +1,11 @@ var searchData= [ - ['unusedbytes_373',['unusedBytes',['../struct_vma_stat_info.html#a1859d290aca2cd582d8dc25922092669',1,'VmaStatInfo']]], - ['unusedrangecount_374',['unusedRangeCount',['../struct_vma_stat_info.html#ae06129c771bfebfd6468a7f4276502a9',1,'VmaStatInfo::unusedRangeCount()'],['../struct_vma_pool_stats.html#ae4f3546ffa4d1e598b64d8e6134854f4',1,'VmaPoolStats::unusedRangeCount()']]], - ['unusedrangesizeavg_375',['unusedRangeSizeAvg',['../struct_vma_stat_info.html#a2f9b3452af90c9768a30b7fb6ae194fc',1,'VmaStatInfo']]], - ['unusedrangesizemax_376',['unusedRangeSizeMax',['../struct_vma_stat_info.html#a5ba1a2476c4d39b10f7e2f7ebbb72ac4',1,'VmaStatInfo::unusedRangeSizeMax()'],['../struct_vma_pool_stats.html#ab4c8f52dd42ab01998f60f0b6acc722b',1,'VmaPoolStats::unusedRangeSizeMax()']]], - ['unusedrangesizemin_377',['unusedRangeSizeMin',['../struct_vma_stat_info.html#aedeba931324f16589cd2416c0d2dd0d4',1,'VmaStatInfo']]], - ['unusedsize_378',['unusedSize',['../struct_vma_pool_stats.html#ad7c54874724fce7b06aba526202d82a8',1,'VmaPoolStats']]], - ['usage_379',['usage',['../struct_vma_budget.html#a84dd1ecca8b0110259eb206dbadb11f6',1,'VmaBudget::usage()'],['../struct_vma_allocation_create_info.html#accb8b06b1f677d858cb9af20705fa910',1,'VmaAllocationCreateInfo::usage()']]], - ['usedbytes_380',['usedBytes',['../struct_vma_stat_info.html#ab0c6c73837e5a70c749fbd4f6064895a',1,'VmaStatInfo']]] + ['unusedbytes_371',['unusedBytes',['../struct_vma_stat_info.html#a1859d290aca2cd582d8dc25922092669',1,'VmaStatInfo']]], + ['unusedrangecount_372',['unusedRangeCount',['../struct_vma_stat_info.html#ae06129c771bfebfd6468a7f4276502a9',1,'VmaStatInfo::unusedRangeCount()'],['../struct_vma_pool_stats.html#ae4f3546ffa4d1e598b64d8e6134854f4',1,'VmaPoolStats::unusedRangeCount()']]], + ['unusedrangesizeavg_373',['unusedRangeSizeAvg',['../struct_vma_stat_info.html#a2f9b3452af90c9768a30b7fb6ae194fc',1,'VmaStatInfo']]], + ['unusedrangesizemax_374',['unusedRangeSizeMax',['../struct_vma_stat_info.html#a5ba1a2476c4d39b10f7e2f7ebbb72ac4',1,'VmaStatInfo::unusedRangeSizeMax()'],['../struct_vma_pool_stats.html#ab4c8f52dd42ab01998f60f0b6acc722b',1,'VmaPoolStats::unusedRangeSizeMax()']]], + ['unusedrangesizemin_375',['unusedRangeSizeMin',['../struct_vma_stat_info.html#aedeba931324f16589cd2416c0d2dd0d4',1,'VmaStatInfo']]], + ['unusedsize_376',['unusedSize',['../struct_vma_pool_stats.html#ad7c54874724fce7b06aba526202d82a8',1,'VmaPoolStats']]], + ['usage_377',['usage',['../struct_vma_budget.html#a84dd1ecca8b0110259eb206dbadb11f6',1,'VmaBudget::usage()'],['../struct_vma_allocation_create_info.html#accb8b06b1f677d858cb9af20705fa910',1,'VmaAllocationCreateInfo::usage()']]], + ['usedbytes_378',['usedBytes',['../struct_vma_stat_info.html#ab0c6c73837e5a70c749fbd4f6064895a',1,'VmaStatInfo']]] ]; diff --git a/docs/html/search/variables_d.js b/docs/html/search/variables_d.js index fe41f7e..54b59a5 100644 --- a/docs/html/search/variables_d.js +++ b/docs/html/search/variables_d.js @@ -1,21 +1,21 @@ var searchData= [ - ['vkallocatememory_381',['vkAllocateMemory',['../struct_vma_vulkan_functions.html#a2943bf99dfd784a0e8f599d987e22e6c',1,'VmaVulkanFunctions']]], - ['vkbindbuffermemory_382',['vkBindBufferMemory',['../struct_vma_vulkan_functions.html#a94fc4f3a605d9880bb3c0ba2c2fc80b2',1,'VmaVulkanFunctions']]], - ['vkbindimagememory_383',['vkBindImageMemory',['../struct_vma_vulkan_functions.html#a1338d96a128a5ade648b8d934907c637',1,'VmaVulkanFunctions']]], - ['vkcmdcopybuffer_384',['vkCmdCopyBuffer',['../struct_vma_vulkan_functions.html#ae5c0db8c89a3b82593dc16aa6a49fa3a',1,'VmaVulkanFunctions']]], - ['vkcreatebuffer_385',['vkCreateBuffer',['../struct_vma_vulkan_functions.html#ae8084315a25006271a2edfc3a447519f',1,'VmaVulkanFunctions']]], - ['vkcreateimage_386',['vkCreateImage',['../struct_vma_vulkan_functions.html#a23ebe70be515b9b5010a1d691200e325',1,'VmaVulkanFunctions']]], - ['vkdestroybuffer_387',['vkDestroyBuffer',['../struct_vma_vulkan_functions.html#a7e054606faddb07f0e8556f3ed317d45',1,'VmaVulkanFunctions']]], - ['vkdestroyimage_388',['vkDestroyImage',['../struct_vma_vulkan_functions.html#a90b898227039b1dcb3520f6e91f09ffa',1,'VmaVulkanFunctions']]], - ['vkflushmappedmemoryranges_389',['vkFlushMappedMemoryRanges',['../struct_vma_vulkan_functions.html#a33c322f4c4ad2810f8a9c97a277572f9',1,'VmaVulkanFunctions']]], - ['vkfreememory_390',['vkFreeMemory',['../struct_vma_vulkan_functions.html#a4c658701778564d62034255b5dda91b4',1,'VmaVulkanFunctions']]], - ['vkgetbuffermemoryrequirements_391',['vkGetBufferMemoryRequirements',['../struct_vma_vulkan_functions.html#a5b92901df89a4194b0d12f6071d4d143',1,'VmaVulkanFunctions']]], - ['vkgetimagememoryrequirements_392',['vkGetImageMemoryRequirements',['../struct_vma_vulkan_functions.html#a475f6f49f8debe4d10800592606d53f4',1,'VmaVulkanFunctions']]], - ['vkgetphysicaldevicememoryproperties_393',['vkGetPhysicalDeviceMemoryProperties',['../struct_vma_vulkan_functions.html#a60d25c33bba06bb8592e6875cbaa9830',1,'VmaVulkanFunctions']]], - ['vkgetphysicaldeviceproperties_394',['vkGetPhysicalDeviceProperties',['../struct_vma_vulkan_functions.html#a77b7a74082823e865dd6546623468f96',1,'VmaVulkanFunctions']]], - ['vkinvalidatemappedmemoryranges_395',['vkInvalidateMappedMemoryRanges',['../struct_vma_vulkan_functions.html#a5c1093bc32386a8060c37c9f282078a1',1,'VmaVulkanFunctions']]], - ['vkmapmemory_396',['vkMapMemory',['../struct_vma_vulkan_functions.html#ab5c1f38dea3a2cf00dc9eb4f57218c49',1,'VmaVulkanFunctions']]], - ['vkunmapmemory_397',['vkUnmapMemory',['../struct_vma_vulkan_functions.html#acc798589736f0becb317fc2196c1d8b9',1,'VmaVulkanFunctions']]], - ['vulkanapiversion_398',['vulkanApiVersion',['../struct_vma_allocator_create_info.html#ae0ffc55139b54520a6bb704b29ffc285',1,'VmaAllocatorCreateInfo']]] + ['vkallocatememory_379',['vkAllocateMemory',['../struct_vma_vulkan_functions.html#a2943bf99dfd784a0e8f599d987e22e6c',1,'VmaVulkanFunctions']]], + ['vkbindbuffermemory_380',['vkBindBufferMemory',['../struct_vma_vulkan_functions.html#a94fc4f3a605d9880bb3c0ba2c2fc80b2',1,'VmaVulkanFunctions']]], + ['vkbindimagememory_381',['vkBindImageMemory',['../struct_vma_vulkan_functions.html#a1338d96a128a5ade648b8d934907c637',1,'VmaVulkanFunctions']]], + ['vkcmdcopybuffer_382',['vkCmdCopyBuffer',['../struct_vma_vulkan_functions.html#ae5c0db8c89a3b82593dc16aa6a49fa3a',1,'VmaVulkanFunctions']]], + ['vkcreatebuffer_383',['vkCreateBuffer',['../struct_vma_vulkan_functions.html#ae8084315a25006271a2edfc3a447519f',1,'VmaVulkanFunctions']]], + ['vkcreateimage_384',['vkCreateImage',['../struct_vma_vulkan_functions.html#a23ebe70be515b9b5010a1d691200e325',1,'VmaVulkanFunctions']]], + ['vkdestroybuffer_385',['vkDestroyBuffer',['../struct_vma_vulkan_functions.html#a7e054606faddb07f0e8556f3ed317d45',1,'VmaVulkanFunctions']]], + ['vkdestroyimage_386',['vkDestroyImage',['../struct_vma_vulkan_functions.html#a90b898227039b1dcb3520f6e91f09ffa',1,'VmaVulkanFunctions']]], + ['vkflushmappedmemoryranges_387',['vkFlushMappedMemoryRanges',['../struct_vma_vulkan_functions.html#a33c322f4c4ad2810f8a9c97a277572f9',1,'VmaVulkanFunctions']]], + ['vkfreememory_388',['vkFreeMemory',['../struct_vma_vulkan_functions.html#a4c658701778564d62034255b5dda91b4',1,'VmaVulkanFunctions']]], + ['vkgetbuffermemoryrequirements_389',['vkGetBufferMemoryRequirements',['../struct_vma_vulkan_functions.html#a5b92901df89a4194b0d12f6071d4d143',1,'VmaVulkanFunctions']]], + ['vkgetimagememoryrequirements_390',['vkGetImageMemoryRequirements',['../struct_vma_vulkan_functions.html#a475f6f49f8debe4d10800592606d53f4',1,'VmaVulkanFunctions']]], + ['vkgetphysicaldevicememoryproperties_391',['vkGetPhysicalDeviceMemoryProperties',['../struct_vma_vulkan_functions.html#a60d25c33bba06bb8592e6875cbaa9830',1,'VmaVulkanFunctions']]], + ['vkgetphysicaldeviceproperties_392',['vkGetPhysicalDeviceProperties',['../struct_vma_vulkan_functions.html#a77b7a74082823e865dd6546623468f96',1,'VmaVulkanFunctions']]], + ['vkinvalidatemappedmemoryranges_393',['vkInvalidateMappedMemoryRanges',['../struct_vma_vulkan_functions.html#a5c1093bc32386a8060c37c9f282078a1',1,'VmaVulkanFunctions']]], + ['vkmapmemory_394',['vkMapMemory',['../struct_vma_vulkan_functions.html#ab5c1f38dea3a2cf00dc9eb4f57218c49',1,'VmaVulkanFunctions']]], + ['vkunmapmemory_395',['vkUnmapMemory',['../struct_vma_vulkan_functions.html#acc798589736f0becb317fc2196c1d8b9',1,'VmaVulkanFunctions']]], + ['vulkanapiversion_396',['vulkanApiVersion',['../struct_vma_allocator_create_info.html#ae0ffc55139b54520a6bb704b29ffc285',1,'VmaAllocatorCreateInfo']]] ]; diff --git a/docs/html/struct_vma_defragmentation_info.html b/docs/html/struct_vma_defragmentation_info.html index 32f45f6..aca85f0 100644 --- a/docs/html/struct_vma_defragmentation_info.html +++ b/docs/html/struct_vma_defragmentation_info.html @@ -85,7 +85,7 @@ Public Attributes

    Detailed Description

    Deprecated. Optional configuration parameters to be passed to function vmaDefragment().

    -
    Deprecated:
    This is a part of the old interface. It is recommended to use structure VmaDefragmentationInfo2 and function vmaDefragmentationBegin() instead.
    +
    Deprecated:
    This is a part of the old interface. It is recommended to use structure VmaDefragmentationInfo2 and function vmaDefragmentationBegin() instead.

    Member Data Documentation

    ◆ maxAllocationsToMove

    diff --git a/docs/html/vk__mem__alloc_8h.html b/docs/html/vk__mem__alloc_8h.html index 1ddad5a..2b33450 100644 --- a/docs/html/vk__mem__alloc_8h.html +++ b/docs/html/vk__mem__alloc_8h.html @@ -387,9 +387,6 @@ Functions void vmaFreeMemoryPages (VmaAllocator allocator, size_t allocationCount, const VmaAllocation *pAllocations)  Frees memory and destroys multiple allocations. More...
      -VkResult vmaResizeAllocation (VmaAllocator allocator, VmaAllocation allocation, VkDeviceSize newSize) - Deprecated. More...
    -  void vmaGetAllocationInfo (VmaAllocator allocator, VmaAllocation allocation, VmaAllocationInfo *pAllocationInfo)  Returns current information about specified allocation and atomically marks it as used in current frame. More...
      @@ -787,7 +784,7 @@ Functions

    Deprecated. Optional configuration parameters to be passed to function vmaDefragment().

    -
    Deprecated:
    This is a part of the old interface. It is recommended to use structure VmaDefragmentationInfo2 and function vmaDefragmentationBegin() instead.
    +
    Deprecated:
    This is a part of the old interface. It is recommended to use structure VmaDefragmentationInfo2 and function vmaDefragmentationBegin() instead.
    @@ -2204,7 +2201,7 @@ Functions
    Returns
    VK_SUCCESS if completed, negative error code in case of error.
    -
    Deprecated:
    This is a part of the old interface. It is recommended to use structure VmaDefragmentationInfo2 and function vmaDefragmentationBegin() instead.
    +
    Deprecated:
    This is a part of the old interface. It is recommended to use structure VmaDefragmentationInfo2 and function vmaDefragmentationBegin() instead.

    This function works by moving allocations to different places (different VkDeviceMemory objects and/or different offsets) in order to optimize memory usage. Only allocations that are in pAllocations array can be moved. All other allocations are considered nonmovable in this call. Basic rules:

    • Only allocations made in memory types that have VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT and VK_MEMORY_PROPERTY_HOST_COHERENT_BIT flags can be compacted. You may pass other allocations but it makes no sense - these will never be moved.
    • @@ -3313,43 +3310,6 @@ Functions

      This function always fails when called for allocation that was created with VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT flag. Such allocations cannot be mapped.

      This function doesn't automatically flush or invalidate caches. If the allocation is made from a memory types that is not HOST_COHERENT, you also need to use vmaInvalidateAllocation() / vmaFlushAllocation(), as required by Vulkan specification.

      - - - -

      ◆ vmaResizeAllocation()

      - -
      -
      - - - - - - - - - - - - - - - - - - - - - - - - -
      VkResult vmaResizeAllocation (VmaAllocator allocator,
      VmaAllocation allocation,
      VkDeviceSize newSize 
      )
      -
      - -

      Deprecated.

      -
      Deprecated:
      In version 2.2.0 it used to try to change allocation's size without moving or reallocating it. In current version it returns VK_SUCCESS only if newSize equals current allocation's size. Otherwise returns VK_ERROR_OUT_OF_POOL_MEMORY, indicating that allocation's size could not be changed.
      -
      diff --git a/docs/html/vk__mem__alloc_8h_source.html b/docs/html/vk__mem__alloc_8h_source.html index 5aef1d2..1d862db 100644 --- a/docs/html/vk__mem__alloc_8h_source.html +++ b/docs/html/vk__mem__alloc_8h_source.html @@ -636,15431 +636,15693 @@ $(function() {
      3368  size_t allocationCount,
      3369  const VmaAllocation VMA_NULLABLE * VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pAllocations);
      3370 
      -
      3378 VMA_CALL_PRE VkResult VMA_CALL_POST vmaResizeAllocation(
      -
      3379  VmaAllocator VMA_NOT_NULL allocator,
      -
      3380  VmaAllocation VMA_NOT_NULL allocation,
      -
      3381  VkDeviceSize newSize);
      -
      3382 
      -
      3399 VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo(
      -
      3400  VmaAllocator VMA_NOT_NULL allocator,
      -
      3401  VmaAllocation VMA_NOT_NULL allocation,
      -
      3402  VmaAllocationInfo* VMA_NOT_NULL pAllocationInfo);
      -
      3403 
      -
      3418 VMA_CALL_PRE VkBool32 VMA_CALL_POST vmaTouchAllocation(
      -
      3419  VmaAllocator VMA_NOT_NULL allocator,
      -
      3420  VmaAllocation VMA_NOT_NULL allocation);
      -
      3421 
      -
      3435 VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationUserData(
      -
      3436  VmaAllocator VMA_NOT_NULL allocator,
      -
      3437  VmaAllocation VMA_NOT_NULL allocation,
      -
      3438  void* VMA_NULLABLE pUserData);
      -
      3439 
      -
      3450 VMA_CALL_PRE void VMA_CALL_POST vmaCreateLostAllocation(
      -
      3451  VmaAllocator VMA_NOT_NULL allocator,
      -
      3452  VmaAllocation VMA_NULLABLE * VMA_NOT_NULL pAllocation);
      -
      3453 
      -
      3492 VMA_CALL_PRE VkResult VMA_CALL_POST vmaMapMemory(
      -
      3493  VmaAllocator VMA_NOT_NULL allocator,
      -
      3494  VmaAllocation VMA_NOT_NULL allocation,
      -
      3495  void* VMA_NULLABLE * VMA_NOT_NULL ppData);
      +
      3387 VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo(
      +
      3388  VmaAllocator VMA_NOT_NULL allocator,
      +
      3389  VmaAllocation VMA_NOT_NULL allocation,
      +
      3390  VmaAllocationInfo* VMA_NOT_NULL pAllocationInfo);
      +
      3391 
      +
      3406 VMA_CALL_PRE VkBool32 VMA_CALL_POST vmaTouchAllocation(
      +
      3407  VmaAllocator VMA_NOT_NULL allocator,
      +
      3408  VmaAllocation VMA_NOT_NULL allocation);
      +
      3409 
      +
      3423 VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationUserData(
      +
      3424  VmaAllocator VMA_NOT_NULL allocator,
      +
      3425  VmaAllocation VMA_NOT_NULL allocation,
      +
      3426  void* VMA_NULLABLE pUserData);
      +
      3427 
      +
      3438 VMA_CALL_PRE void VMA_CALL_POST vmaCreateLostAllocation(
      +
      3439  VmaAllocator VMA_NOT_NULL allocator,
      +
      3440  VmaAllocation VMA_NULLABLE * VMA_NOT_NULL pAllocation);
      +
      3441 
      +
      3480 VMA_CALL_PRE VkResult VMA_CALL_POST vmaMapMemory(
      +
      3481  VmaAllocator VMA_NOT_NULL allocator,
      +
      3482  VmaAllocation VMA_NOT_NULL allocation,
      +
      3483  void* VMA_NULLABLE * VMA_NOT_NULL ppData);
      +
      3484 
      +
      3493 VMA_CALL_PRE void VMA_CALL_POST vmaUnmapMemory(
      +
      3494  VmaAllocator VMA_NOT_NULL allocator,
      +
      3495  VmaAllocation VMA_NOT_NULL allocation);
      3496 
      -
      3505 VMA_CALL_PRE void VMA_CALL_POST vmaUnmapMemory(
      -
      3506  VmaAllocator VMA_NOT_NULL allocator,
      -
      3507  VmaAllocation VMA_NOT_NULL allocation);
      -
      3508 
      -
      3530 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocation(
      -
      3531  VmaAllocator VMA_NOT_NULL allocator,
      -
      3532  VmaAllocation VMA_NOT_NULL allocation,
      -
      3533  VkDeviceSize offset,
      -
      3534  VkDeviceSize size);
      -
      3535 
      -
      3557 VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation(
      -
      3558  VmaAllocator VMA_NOT_NULL allocator,
      -
      3559  VmaAllocation VMA_NOT_NULL allocation,
      -
      3560  VkDeviceSize offset,
      -
      3561  VkDeviceSize size);
      -
      3562 
      -
      3577 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations(
      -
      3578  VmaAllocator VMA_NOT_NULL allocator,
      -
      3579  uint32_t allocationCount,
      -
      3580  const VmaAllocation VMA_NOT_NULL * VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) allocations,
      -
      3581  const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) offsets,
      -
      3582  const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) sizes);
      -
      3583 
      -
      3598 VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations(
      -
      3599  VmaAllocator VMA_NOT_NULL allocator,
      -
      3600  uint32_t allocationCount,
      -
      3601  const VmaAllocation VMA_NOT_NULL * VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) allocations,
      -
      3602  const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) offsets,
      -
      3603  const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) sizes);
      -
      3604 
      -
      3621 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption(VmaAllocator VMA_NOT_NULL allocator, uint32_t memoryTypeBits);
      -
      3622 
      -
      3629 VK_DEFINE_HANDLE(VmaDefragmentationContext)
      -
      3630 
      -
      3631 typedef enum VmaDefragmentationFlagBits {
      - - - -
      3636 typedef VkFlags VmaDefragmentationFlags;
      -
      3637 
      -
      3642 typedef struct VmaDefragmentationInfo2 {
      - - -
      3657  const VmaAllocation VMA_NOT_NULL * VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) pAllocations;
      -
      3663  VkBool32* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) pAllocationsChanged;
      -
      3666  uint32_t poolCount;
      -
      3682  const VmaPool VMA_NOT_NULL * VMA_NULLABLE VMA_LEN_IF_NOT_NULL(poolCount) pPools;
      -
      3687  VkDeviceSize maxCpuBytesToMove;
      - -
      3697  VkDeviceSize maxGpuBytesToMove;
      - -
      3711  VkCommandBuffer VMA_NULLABLE commandBuffer;
      - -
      3713 
      - - -
      3716  VkDeviceMemory VMA_NOT_NULL_NON_DISPATCHABLE memory;
      -
      3717  VkDeviceSize offset;
      - -
      3719 
      - -
      3725  uint32_t moveCount;
      -
      3726  VmaDefragmentationPassMoveInfo* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(moveCount) pMoves;
      - -
      3728 
      -
      3733 typedef struct VmaDefragmentationInfo {
      -
      3738  VkDeviceSize maxBytesToMove;
      - - +
      3518 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocation(
      +
      3519  VmaAllocator VMA_NOT_NULL allocator,
      +
      3520  VmaAllocation VMA_NOT_NULL allocation,
      +
      3521  VkDeviceSize offset,
      +
      3522  VkDeviceSize size);
      +
      3523 
      +
      3545 VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation(
      +
      3546  VmaAllocator VMA_NOT_NULL allocator,
      +
      3547  VmaAllocation VMA_NOT_NULL allocation,
      +
      3548  VkDeviceSize offset,
      +
      3549  VkDeviceSize size);
      +
      3550 
      +
      3565 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations(
      +
      3566  VmaAllocator VMA_NOT_NULL allocator,
      +
      3567  uint32_t allocationCount,
      +
      3568  const VmaAllocation VMA_NOT_NULL * VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) allocations,
      +
      3569  const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) offsets,
      +
      3570  const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) sizes);
      +
      3571 
      +
      3586 VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations(
      +
      3587  VmaAllocator VMA_NOT_NULL allocator,
      +
      3588  uint32_t allocationCount,
      +
      3589  const VmaAllocation VMA_NOT_NULL * VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) allocations,
      +
      3590  const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) offsets,
      +
      3591  const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) sizes);
      +
      3592 
      +
      3609 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption(VmaAllocator VMA_NOT_NULL allocator, uint32_t memoryTypeBits);
      +
      3610 
      +
      3617 VK_DEFINE_HANDLE(VmaDefragmentationContext)
      +
      3618 
      +
      3619 typedef enum VmaDefragmentationFlagBits {
      + + + +
      3624 typedef VkFlags VmaDefragmentationFlags;
      +
      3625 
      +
      3630 typedef struct VmaDefragmentationInfo2 {
      + + +
      3645  const VmaAllocation VMA_NOT_NULL * VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) pAllocations;
      +
      3651  VkBool32* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) pAllocationsChanged;
      +
      3654  uint32_t poolCount;
      +
      3670  const VmaPool VMA_NOT_NULL * VMA_NULLABLE VMA_LEN_IF_NOT_NULL(poolCount) pPools;
      +
      3675  VkDeviceSize maxCpuBytesToMove;
      + +
      3685  VkDeviceSize maxGpuBytesToMove;
      + +
      3699  VkCommandBuffer VMA_NULLABLE commandBuffer;
      + +
      3701 
      + + +
      3704  VkDeviceMemory VMA_NOT_NULL_NON_DISPATCHABLE memory;
      +
      3705  VkDeviceSize offset;
      + +
      3707 
      + +
      3713  uint32_t moveCount;
      +
      3714  VmaDefragmentationPassMoveInfo* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(moveCount) pMoves;
      + +
      3716 
      +
      3721 typedef struct VmaDefragmentationInfo {
      +
      3726  VkDeviceSize maxBytesToMove;
      + + +
      3733 
      +
      3735 typedef struct VmaDefragmentationStats {
      +
      3737  VkDeviceSize bytesMoved;
      +
      3739  VkDeviceSize bytesFreed;
      + + +
      3745 
      -
      3747 typedef struct VmaDefragmentationStats {
      -
      3749  VkDeviceSize bytesMoved;
      -
      3751  VkDeviceSize bytesFreed;
      - - - -
      3757 
      -
      3787 VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragmentationBegin(
      -
      3788  VmaAllocator VMA_NOT_NULL allocator,
      -
      3789  const VmaDefragmentationInfo2* VMA_NOT_NULL pInfo,
      -
      3790  VmaDefragmentationStats* VMA_NULLABLE pStats,
      -
      3791  VmaDefragmentationContext VMA_NULLABLE * VMA_NOT_NULL pContext);
      -
      3792 
      -
      3798 VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragmentationEnd(
      -
      3799  VmaAllocator VMA_NOT_NULL allocator,
      -
      3800  VmaDefragmentationContext VMA_NULLABLE context);
      -
      3801 
      -
      3802 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentationPass(
      -
      3803  VmaAllocator VMA_NOT_NULL allocator,
      -
      3804  VmaDefragmentationContext VMA_NULLABLE context,
      -
      3805  VmaDefragmentationPassInfo* VMA_NOT_NULL pInfo
      -
      3806 );
      -
      3807 VMA_CALL_PRE VkResult VMA_CALL_POST vmaEndDefragmentationPass(
      -
      3808  VmaAllocator VMA_NOT_NULL allocator,
      -
      3809  VmaDefragmentationContext VMA_NULLABLE context
      -
      3810 );
      -
      3811 
      -
      3852 VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragment(
      -
      3853  VmaAllocator VMA_NOT_NULL allocator,
      -
      3854  const VmaAllocation VMA_NOT_NULL * VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pAllocations,
      -
      3855  size_t allocationCount,
      -
      3856  VkBool32* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) pAllocationsChanged,
      -
      3857  const VmaDefragmentationInfo* VMA_NULLABLE pDefragmentationInfo,
      -
      3858  VmaDefragmentationStats* VMA_NULLABLE pDefragmentationStats);
      -
      3859 
      -
      3872 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory(
      -
      3873  VmaAllocator VMA_NOT_NULL allocator,
      -
      3874  VmaAllocation VMA_NOT_NULL allocation,
      -
      3875  VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer);
      -
      3876 
      -
      3887 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory2(
      -
      3888  VmaAllocator VMA_NOT_NULL allocator,
      -
      3889  VmaAllocation VMA_NOT_NULL allocation,
      -
      3890  VkDeviceSize allocationLocalOffset,
      -
      3891  VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer,
      -
      3892  const void* VMA_NULLABLE pNext);
      -
      3893 
      -
      3906 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory(
      -
      3907  VmaAllocator VMA_NOT_NULL allocator,
      -
      3908  VmaAllocation VMA_NOT_NULL allocation,
      -
      3909  VkImage VMA_NOT_NULL_NON_DISPATCHABLE image);
      -
      3910 
      -
      3921 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory2(
      -
      3922  VmaAllocator VMA_NOT_NULL allocator,
      -
      3923  VmaAllocation VMA_NOT_NULL allocation,
      -
      3924  VkDeviceSize allocationLocalOffset,
      -
      3925  VkImage VMA_NOT_NULL_NON_DISPATCHABLE image,
      -
      3926  const void* VMA_NULLABLE pNext);
      -
      3927 
      -
      3958 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer(
      -
      3959  VmaAllocator VMA_NOT_NULL allocator,
      -
      3960  const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo,
      -
      3961  const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo,
      -
      3962  VkBuffer VMA_NULLABLE_NON_DISPATCHABLE * VMA_NOT_NULL pBuffer,
      -
      3963  VmaAllocation VMA_NULLABLE * VMA_NOT_NULL pAllocation,
      -
      3964  VmaAllocationInfo* VMA_NULLABLE pAllocationInfo);
      -
      3965 
      -
      3977 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer(
      -
      3978  VmaAllocator VMA_NOT_NULL allocator,
      -
      3979  VkBuffer VMA_NULLABLE_NON_DISPATCHABLE buffer,
      -
      3980  VmaAllocation VMA_NULLABLE allocation);
      -
      3981 
      -
      3983 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage(
      -
      3984  VmaAllocator VMA_NOT_NULL allocator,
      -
      3985  const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo,
      -
      3986  const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo,
      -
      3987  VkImage VMA_NULLABLE_NON_DISPATCHABLE * VMA_NOT_NULL pImage,
      -
      3988  VmaAllocation VMA_NULLABLE * VMA_NOT_NULL pAllocation,
      -
      3989  VmaAllocationInfo* VMA_NULLABLE pAllocationInfo);
      -
      3990 
      -
      4002 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage(
      -
      4003  VmaAllocator VMA_NOT_NULL allocator,
      -
      4004  VkImage VMA_NULLABLE_NON_DISPATCHABLE image,
      -
      4005  VmaAllocation VMA_NULLABLE allocation);
      -
      4006 
      -
      4007 #ifdef __cplusplus
      -
      4008 }
      -
      4009 #endif
      -
      4010 
      -
      4011 #endif // AMD_VULKAN_MEMORY_ALLOCATOR_H
      -
      4012 
      -
      4013 // For Visual Studio IntelliSense.
      -
      4014 #if defined(__cplusplus) && defined(__INTELLISENSE__)
      -
      4015 #define VMA_IMPLEMENTATION
      -
      4016 #endif
      -
      4017 
      -
      4018 #ifdef VMA_IMPLEMENTATION
      -
      4019 #undef VMA_IMPLEMENTATION
      -
      4020 
      -
      4021 #include <cstdint>
      -
      4022 #include <cstdlib>
      -
      4023 #include <cstring>
      -
      4024 #include <utility>
      -
      4025 
      -
      4026 #if VMA_RECORDING_ENABLED
      -
      4027  #include <chrono>
      -
      4028  #if defined(_WIN32)
      -
      4029  #include <windows.h>
      -
      4030  #else
      -
      4031  #include <sstream>
      -
      4032  #include <thread>
      -
      4033  #endif
      -
      4034 #endif
      -
      4035 
      -
      4036 /*******************************************************************************
      -
      4037 CONFIGURATION SECTION
      -
      4038 
      -
      4039 Define some of these macros before each #include of this header or change them
      -
      4040 here if you need other then default behavior depending on your environment.
      -
      4041 */
      -
      4042 
      -
      4043 /*
      -
      4044 Define this macro to 1 to make the library fetch pointers to Vulkan functions
      -
      4045 internally, like:
      -
      4046 
      -
      4047  vulkanFunctions.vkAllocateMemory = &vkAllocateMemory;
      -
      4048 */
      -
      4049 #if !defined(VMA_STATIC_VULKAN_FUNCTIONS) && !defined(VK_NO_PROTOTYPES)
      -
      4050  #define VMA_STATIC_VULKAN_FUNCTIONS 1
      -
      4051 #endif
      -
      4052 
      -
      4053 /*
      -
      4054 Define this macro to 1 to make the library fetch pointers to Vulkan functions
      -
      4055 internally, like:
      -
      4056 
      -
      4057  vulkanFunctions.vkAllocateMemory = (PFN_vkAllocateMemory)vkGetDeviceProcAddr(m_hDevice, vkAllocateMemory);
      -
      4058 */
      -
      4059 #if !defined(VMA_DYNAMIC_VULKAN_FUNCTIONS)
      -
      4060  #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
      -
      4061  #if defined(VK_NO_PROTOTYPES)
      -
      4062  extern PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
      -
      4063  extern PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr;
      -
      4064  #endif
      -
      4065 #endif
      -
      4066 
      -
      4067 // Define this macro to 1 to make the library use STL containers instead of its own implementation.
      -
      4068 //#define VMA_USE_STL_CONTAINERS 1
      +
      3775 VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragmentationBegin(
      +
      3776  VmaAllocator VMA_NOT_NULL allocator,
      +
      3777  const VmaDefragmentationInfo2* VMA_NOT_NULL pInfo,
      +
      3778  VmaDefragmentationStats* VMA_NULLABLE pStats,
      +
      3779  VmaDefragmentationContext VMA_NULLABLE * VMA_NOT_NULL pContext);
      +
      3780 
      +
      3786 VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragmentationEnd(
      +
      3787  VmaAllocator VMA_NOT_NULL allocator,
      +
      3788  VmaDefragmentationContext VMA_NULLABLE context);
      +
      3789 
      +
      3790 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentationPass(
      +
      3791  VmaAllocator VMA_NOT_NULL allocator,
      +
      3792  VmaDefragmentationContext VMA_NULLABLE context,
      +
      3793  VmaDefragmentationPassInfo* VMA_NOT_NULL pInfo
      +
      3794 );
      +
      3795 VMA_CALL_PRE VkResult VMA_CALL_POST vmaEndDefragmentationPass(
      +
      3796  VmaAllocator VMA_NOT_NULL allocator,
      +
      3797  VmaDefragmentationContext VMA_NULLABLE context
      +
      3798 );
      +
      3799 
      +
      3840 VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragment(
      +
      3841  VmaAllocator VMA_NOT_NULL allocator,
      +
      3842  const VmaAllocation VMA_NOT_NULL * VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pAllocations,
      +
      3843  size_t allocationCount,
      +
      3844  VkBool32* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) pAllocationsChanged,
      +
      3845  const VmaDefragmentationInfo* VMA_NULLABLE pDefragmentationInfo,
      +
      3846  VmaDefragmentationStats* VMA_NULLABLE pDefragmentationStats);
      +
      3847 
      +
      3860 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory(
      +
      3861  VmaAllocator VMA_NOT_NULL allocator,
      +
      3862  VmaAllocation VMA_NOT_NULL allocation,
      +
      3863  VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer);
      +
      3864 
      +
      3875 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory2(
      +
      3876  VmaAllocator VMA_NOT_NULL allocator,
      +
      3877  VmaAllocation VMA_NOT_NULL allocation,
      +
      3878  VkDeviceSize allocationLocalOffset,
      +
      3879  VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer,
      +
      3880  const void* VMA_NULLABLE pNext);
      +
      3881 
      +
      3894 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory(
      +
      3895  VmaAllocator VMA_NOT_NULL allocator,
      +
      3896  VmaAllocation VMA_NOT_NULL allocation,
      +
      3897  VkImage VMA_NOT_NULL_NON_DISPATCHABLE image);
      +
      3898 
      +
      3909 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory2(
      +
      3910  VmaAllocator VMA_NOT_NULL allocator,
      +
      3911  VmaAllocation VMA_NOT_NULL allocation,
      +
      3912  VkDeviceSize allocationLocalOffset,
      +
      3913  VkImage VMA_NOT_NULL_NON_DISPATCHABLE image,
      +
      3914  const void* VMA_NULLABLE pNext);
      +
      3915 
      +
      3946 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer(
      +
      3947  VmaAllocator VMA_NOT_NULL allocator,
      +
      3948  const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo,
      +
      3949  const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo,
      +
      3950  VkBuffer VMA_NULLABLE_NON_DISPATCHABLE * VMA_NOT_NULL pBuffer,
      +
      3951  VmaAllocation VMA_NULLABLE * VMA_NOT_NULL pAllocation,
      +
      3952  VmaAllocationInfo* VMA_NULLABLE pAllocationInfo);
      +
      3953 
      +
      3965 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer(
      +
      3966  VmaAllocator VMA_NOT_NULL allocator,
      +
      3967  VkBuffer VMA_NULLABLE_NON_DISPATCHABLE buffer,
      +
      3968  VmaAllocation VMA_NULLABLE allocation);
      +
      3969 
      +
      3971 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage(
      +
      3972  VmaAllocator VMA_NOT_NULL allocator,
      +
      3973  const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo,
      +
      3974  const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo,
      +
      3975  VkImage VMA_NULLABLE_NON_DISPATCHABLE * VMA_NOT_NULL pImage,
      +
      3976  VmaAllocation VMA_NULLABLE * VMA_NOT_NULL pAllocation,
      +
      3977  VmaAllocationInfo* VMA_NULLABLE pAllocationInfo);
      +
      3978 
      +
      3990 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage(
      +
      3991  VmaAllocator VMA_NOT_NULL allocator,
      +
      3992  VkImage VMA_NULLABLE_NON_DISPATCHABLE image,
      +
      3993  VmaAllocation VMA_NULLABLE allocation);
      +
      3994 
      +
      3995 #ifdef __cplusplus
      +
      3996 }
      +
      3997 #endif
      +
      3998 
      +
      3999 #endif // AMD_VULKAN_MEMORY_ALLOCATOR_H
      +
      4000 
      +
      4001 // For Visual Studio IntelliSense.
      +
      4002 #if defined(__cplusplus) && defined(__INTELLISENSE__)
      +
      4003 #define VMA_IMPLEMENTATION
      +
      4004 #endif
      +
      4005 
      +
      4006 #ifdef VMA_IMPLEMENTATION
      +
      4007 #undef VMA_IMPLEMENTATION
      +
      4008 
      +
      4009 #include <cstdint>
      +
      4010 #include <cstdlib>
      +
      4011 #include <cstring>
      +
      4012 #include <utility>
      +
      4013 
      +
      4014 #if VMA_RECORDING_ENABLED
      +
      4015  #include <chrono>
      +
      4016  #if defined(_WIN32)
      +
      4017  #include <windows.h>
      +
      4018  #else
      +
      4019  #include <sstream>
      +
      4020  #include <thread>
      +
      4021  #endif
      +
      4022 #endif
      +
      4023 
      +
      4024 /*******************************************************************************
      +
      4025 CONFIGURATION SECTION
      +
      4026 
      +
      4027 Define some of these macros before each #include of this header or change them
      +
      4028 here if you need other then default behavior depending on your environment.
      +
      4029 */
      +
      4030 
      +
      4031 /*
      +
      4032 Define this macro to 1 to make the library fetch pointers to Vulkan functions
      +
      4033 internally, like:
      +
      4034 
      +
      4035  vulkanFunctions.vkAllocateMemory = &vkAllocateMemory;
      +
      4036 */
      +
      4037 #if !defined(VMA_STATIC_VULKAN_FUNCTIONS) && !defined(VK_NO_PROTOTYPES)
      +
      4038  #define VMA_STATIC_VULKAN_FUNCTIONS 1
      +
      4039 #endif
      +
      4040 
      +
      4041 /*
      +
      4042 Define this macro to 1 to make the library fetch pointers to Vulkan functions
      +
      4043 internally, like:
      +
      4044 
      +
      4045  vulkanFunctions.vkAllocateMemory = (PFN_vkAllocateMemory)vkGetDeviceProcAddr(m_hDevice, vkAllocateMemory);
      +
      4046 */
      +
      4047 #if !defined(VMA_DYNAMIC_VULKAN_FUNCTIONS)
      +
      4048  #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
      +
      4049  #if defined(VK_NO_PROTOTYPES)
      +
      4050  extern PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
      +
      4051  extern PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr;
      +
      4052  #endif
      +
      4053 #endif
      +
      4054 
      +
      4055 // Define this macro to 1 to make the library use STL containers instead of its own implementation.
      +
      4056 //#define VMA_USE_STL_CONTAINERS 1
      +
      4057 
      +
      4058 /* Set this macro to 1 to make the library including and using STL containers:
      +
      4059 std::pair, std::vector, std::list, std::unordered_map.
      +
      4060 
      +
      4061 Set it to 0 or undefined to make the library using its own implementation of
      +
      4062 the containers.
      +
      4063 */
      +
      4064 #if VMA_USE_STL_CONTAINERS
      +
      4065  #define VMA_USE_STL_VECTOR 1
      +
      4066  #define VMA_USE_STL_UNORDERED_MAP 1
      +
      4067  #define VMA_USE_STL_LIST 1
      +
      4068 #endif
      4069 
      -
      4070 /* Set this macro to 1 to make the library including and using STL containers:
      -
      4071 std::pair, std::vector, std::list, std::unordered_map.
      -
      4072 
      -
      4073 Set it to 0 or undefined to make the library using its own implementation of
      -
      4074 the containers.
      -
      4075 */
      -
      4076 #if VMA_USE_STL_CONTAINERS
      -
      4077  #define VMA_USE_STL_VECTOR 1
      -
      4078  #define VMA_USE_STL_UNORDERED_MAP 1
      -
      4079  #define VMA_USE_STL_LIST 1
      -
      4080 #endif
      -
      4081 
      -
      4082 #ifndef VMA_USE_STL_SHARED_MUTEX
      -
      4083  // Compiler conforms to C++17.
      -
      4084  #if __cplusplus >= 201703L
      -
      4085  #define VMA_USE_STL_SHARED_MUTEX 1
      -
      4086  // Visual studio defines __cplusplus properly only when passed additional parameter: /Zc:__cplusplus
      -
      4087  // Otherwise it's always 199711L, despite shared_mutex works since Visual Studio 2015 Update 2.
      -
      4088  // See: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
      -
      4089  #elif defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023918 && __cplusplus == 199711L && _MSVC_LANG >= 201703L
      -
      4090  #define VMA_USE_STL_SHARED_MUTEX 1
      -
      4091  #else
      -
      4092  #define VMA_USE_STL_SHARED_MUTEX 0
      -
      4093  #endif
      +
      4070 #ifndef VMA_USE_STL_SHARED_MUTEX
      +
      4071  // Compiler conforms to C++17.
      +
      4072  #if __cplusplus >= 201703L
      +
      4073  #define VMA_USE_STL_SHARED_MUTEX 1
      +
      4074  // Visual studio defines __cplusplus properly only when passed additional parameter: /Zc:__cplusplus
      +
      4075  // Otherwise it's always 199711L, despite shared_mutex works since Visual Studio 2015 Update 2.
      +
      4076  // See: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
      +
      4077  #elif defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023918 && __cplusplus == 199711L && _MSVC_LANG >= 201703L
      +
      4078  #define VMA_USE_STL_SHARED_MUTEX 1
      +
      4079  #else
      +
      4080  #define VMA_USE_STL_SHARED_MUTEX 0
      +
      4081  #endif
      +
      4082 #endif
      +
      4083 
      +
      4084 /*
      +
      4085 THESE INCLUDES ARE NOT ENABLED BY DEFAULT.
      +
      4086 Library has its own container implementation.
      +
      4087 */
      +
      4088 #if VMA_USE_STL_VECTOR
      +
      4089  #include <vector>
      +
      4090 #endif
      +
      4091 
      +
      4092 #if VMA_USE_STL_UNORDERED_MAP
      +
      4093  #include <unordered_map>
      4094 #endif
      4095 
      -
      4096 /*
      -
      4097 THESE INCLUDES ARE NOT ENABLED BY DEFAULT.
      -
      4098 Library has its own container implementation.
      -
      4099 */
      -
      4100 #if VMA_USE_STL_VECTOR
      -
      4101  #include <vector>
      -
      4102 #endif
      -
      4103 
      -
      4104 #if VMA_USE_STL_UNORDERED_MAP
      -
      4105  #include <unordered_map>
      -
      4106 #endif
      +
      4096 #if VMA_USE_STL_LIST
      +
      4097  #include <list>
      +
      4098 #endif
      +
      4099 
      +
      4100 /*
      +
      4101 Following headers are used in this CONFIGURATION section only, so feel free to
      +
      4102 remove them if not needed.
      +
      4103 */
      +
      4104 #include <cassert> // for assert
      +
      4105 #include <algorithm> // for min, max
      +
      4106 #include <mutex>
      4107 
      -
      4108 #if VMA_USE_STL_LIST
      -
      4109  #include <list>
      -
      4110 #endif
      -
      4111 
      -
      4112 /*
      -
      4113 Following headers are used in this CONFIGURATION section only, so feel free to
      -
      4114 remove them if not needed.
      -
      4115 */
      -
      4116 #include <cassert> // for assert
      -
      4117 #include <algorithm> // for min, max
      -
      4118 #include <mutex>
      -
      4119 
      -
      4120 #ifndef VMA_NULL
      -
      4121  // Value used as null pointer. Define it to e.g.: nullptr, NULL, 0, (void*)0.
      -
      4122  #define VMA_NULL nullptr
      -
      4123 #endif
      -
      4124 
      -
      4125 #if defined(__ANDROID_API__) && (__ANDROID_API__ < 16)
      +
      4108 #ifndef VMA_NULL
      +
      4109  // Value used as null pointer. Define it to e.g.: nullptr, NULL, 0, (void*)0.
      +
      4110  #define VMA_NULL nullptr
      +
      4111 #endif
      +
      4112 
      +
      4113 #if defined(__ANDROID_API__) && (__ANDROID_API__ < 16)
      +
      4114 #include <cstdlib>
      +
      4115 static void* vma_aligned_alloc(size_t alignment, size_t size)
      +
      4116 {
      +
      4117  // alignment must be >= sizeof(void*)
      +
      4118  if(alignment < sizeof(void*))
      +
      4119  {
      +
      4120  alignment = sizeof(void*);
      +
      4121  }
      +
      4122 
      +
      4123  return memalign(alignment, size);
      +
      4124 }
      +
      4125 #elif defined(__APPLE__) || defined(__ANDROID__) || (defined(__linux__) && defined(__GLIBCXX__) && !defined(_GLIBCXX_HAVE_ALIGNED_ALLOC))
      4126 #include <cstdlib>
      -
      4127 static void* vma_aligned_alloc(size_t alignment, size_t size)
      -
      4128 {
      -
      4129  // alignment must be >= sizeof(void*)
      -
      4130  if(alignment < sizeof(void*))
      -
      4131  {
      -
      4132  alignment = sizeof(void*);
      -
      4133  }
      -
      4134 
      -
      4135  return memalign(alignment, size);
      -
      4136 }
      -
      4137 #elif defined(__APPLE__) || defined(__ANDROID__) || (defined(__linux__) && defined(__GLIBCXX__) && !defined(_GLIBCXX_HAVE_ALIGNED_ALLOC))
      -
      4138 #include <cstdlib>
      -
      4139 
      -
      4140 #if defined(__APPLE__)
      -
      4141 #include <AvailabilityMacros.h>
      -
      4142 #endif
      -
      4143 
      -
      4144 static void* vma_aligned_alloc(size_t alignment, size_t size)
      -
      4145 {
      -
      4146 #if defined(__APPLE__) && (defined(MAC_OS_X_VERSION_10_16) || defined(__IPHONE_14_0))
      -
      4147 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_16 || __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
      -
      4148  // For C++14, usr/include/malloc/_malloc.h declares aligned_alloc()) only
      -
      4149  // with the MacOSX11.0 SDK in Xcode 12 (which is what adds
      -
      4150  // MAC_OS_X_VERSION_10_16), even though the function is marked
      -
      4151  // availabe for 10.15. That's why the preprocessor checks for 10.16 but
      -
      4152  // the __builtin_available checks for 10.15.
      -
      4153  // People who use C++17 could call aligned_alloc with the 10.15 SDK already.
      -
      4154  if (__builtin_available(macOS 10.15, iOS 13, *))
      -
      4155  return aligned_alloc(alignment, size);
      -
      4156 #endif
      -
      4157 #endif
      -
      4158  // alignment must be >= sizeof(void*)
      -
      4159  if(alignment < sizeof(void*))
      -
      4160  {
      -
      4161  alignment = sizeof(void*);
      -
      4162  }
      -
      4163 
      -
      4164  void *pointer;
      -
      4165  if(posix_memalign(&pointer, alignment, size) == 0)
      -
      4166  return pointer;
      -
      4167  return VMA_NULL;
      -
      4168 }
      -
      4169 #elif defined(_WIN32)
      -
      4170 static void* vma_aligned_alloc(size_t alignment, size_t size)
      +
      4127 
      +
      4128 #if defined(__APPLE__)
      +
      4129 #include <AvailabilityMacros.h>
      +
      4130 #endif
      +
      4131 
      +
      4132 static void* vma_aligned_alloc(size_t alignment, size_t size)
      +
      4133 {
      +
      4134 #if defined(__APPLE__) && (defined(MAC_OS_X_VERSION_10_16) || defined(__IPHONE_14_0))
      +
      4135 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_16 || __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
      +
      4136  // For C++14, usr/include/malloc/_malloc.h declares aligned_alloc()) only
      +
      4137  // with the MacOSX11.0 SDK in Xcode 12 (which is what adds
      +
      4138  // MAC_OS_X_VERSION_10_16), even though the function is marked
      +
      4139  // availabe for 10.15. That's why the preprocessor checks for 10.16 but
      +
      4140  // the __builtin_available checks for 10.15.
      +
      4141  // People who use C++17 could call aligned_alloc with the 10.15 SDK already.
      +
      4142  if (__builtin_available(macOS 10.15, iOS 13, *))
      +
      4143  return aligned_alloc(alignment, size);
      +
      4144 #endif
      +
      4145 #endif
      +
      4146  // alignment must be >= sizeof(void*)
      +
      4147  if(alignment < sizeof(void*))
      +
      4148  {
      +
      4149  alignment = sizeof(void*);
      +
      4150  }
      +
      4151 
      +
      4152  void *pointer;
      +
      4153  if(posix_memalign(&pointer, alignment, size) == 0)
      +
      4154  return pointer;
      +
      4155  return VMA_NULL;
      +
      4156 }
      +
      4157 #elif defined(_WIN32)
      +
      4158 static void* vma_aligned_alloc(size_t alignment, size_t size)
      +
      4159 {
      +
      4160  return _aligned_malloc(size, alignment);
      +
      4161 }
      +
      4162 #else
      +
      4163 static void* vma_aligned_alloc(size_t alignment, size_t size)
      +
      4164 {
      +
      4165  return aligned_alloc(alignment, size);
      +
      4166 }
      +
      4167 #endif
      +
      4168 
      +
      4169 #if defined(_WIN32)
      +
      4170 static void vma_aligned_free(void* ptr)
      4171 {
      -
      4172  return _aligned_malloc(size, alignment);
      +
      4172  _aligned_free(ptr);
      4173 }
      4174 #else
      -
      4175 static void* vma_aligned_alloc(size_t alignment, size_t size)
      +
      4175 static void vma_aligned_free(void* ptr)
      4176 {
      -
      4177  return aligned_alloc(alignment, size);
      +
      4177  free(ptr);
      4178 }
      4179 #endif
      4180 
      -
      4181 #if defined(_WIN32)
      -
      4182 static void vma_aligned_free(void* ptr)
      -
      4183 {
      -
      4184  _aligned_free(ptr);
      -
      4185 }
      -
      4186 #else
      -
      4187 static void vma_aligned_free(void* ptr)
      -
      4188 {
      -
      4189  free(ptr);
      -
      4190 }
      -
      4191 #endif
      -
      4192 
      -
      4193 // If your compiler is not compatible with C++11 and definition of
      -
      4194 // aligned_alloc() function is missing, uncommeting following line may help:
      -
      4195 
      -
      4196 //#include <malloc.h>
      -
      4197 
      -
      4198 // Normal assert to check for programmer's errors, especially in Debug configuration.
      -
      4199 #ifndef VMA_ASSERT
      -
      4200  #ifdef NDEBUG
      -
      4201  #define VMA_ASSERT(expr)
      -
      4202  #else
      -
      4203  #define VMA_ASSERT(expr) assert(expr)
      -
      4204  #endif
      -
      4205 #endif
      -
      4206 
      -
      4207 // Assert that will be called very often, like inside data structures e.g. operator[].
      -
      4208 // Making it non-empty can make program slow.
      -
      4209 #ifndef VMA_HEAVY_ASSERT
      -
      4210  #ifdef NDEBUG
      -
      4211  #define VMA_HEAVY_ASSERT(expr)
      -
      4212  #else
      -
      4213  #define VMA_HEAVY_ASSERT(expr) //VMA_ASSERT(expr)
      -
      4214  #endif
      -
      4215 #endif
      -
      4216 
      -
      4217 #ifndef VMA_ALIGN_OF
      -
      4218  #define VMA_ALIGN_OF(type) (__alignof(type))
      -
      4219 #endif
      -
      4220 
      -
      4221 #ifndef VMA_SYSTEM_ALIGNED_MALLOC
      -
      4222  #define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) vma_aligned_alloc((alignment), (size))
      -
      4223 #endif
      -
      4224 
      -
      4225 #ifndef VMA_SYSTEM_ALIGNED_FREE
      -
      4226  // VMA_SYSTEM_FREE is the old name, but might have been defined by the user
      -
      4227  #if defined(VMA_SYSTEM_FREE)
      -
      4228  #define VMA_SYSTEM_ALIGNED_FREE(ptr) VMA_SYSTEM_FREE(ptr)
      -
      4229  #else
      -
      4230  #define VMA_SYSTEM_ALIGNED_FREE(ptr) vma_aligned_free(ptr)
      -
      4231  #endif
      +
      4181 // If your compiler is not compatible with C++11 and definition of
      +
      4182 // aligned_alloc() function is missing, uncommeting following line may help:
      +
      4183 
      +
      4184 //#include <malloc.h>
      +
      4185 
      +
      4186 // Normal assert to check for programmer's errors, especially in Debug configuration.
      +
      4187 #ifndef VMA_ASSERT
      +
      4188  #ifdef NDEBUG
      +
      4189  #define VMA_ASSERT(expr)
      +
      4190  #else
      +
      4191  #define VMA_ASSERT(expr) assert(expr)
      +
      4192  #endif
      +
      4193 #endif
      +
      4194 
      +
      4195 // Assert that will be called very often, like inside data structures e.g. operator[].
      +
      4196 // Making it non-empty can make program slow.
      +
      4197 #ifndef VMA_HEAVY_ASSERT
      +
      4198  #ifdef NDEBUG
      +
      4199  #define VMA_HEAVY_ASSERT(expr)
      +
      4200  #else
      +
      4201  #define VMA_HEAVY_ASSERT(expr) //VMA_ASSERT(expr)
      +
      4202  #endif
      +
      4203 #endif
      +
      4204 
      +
      4205 #ifndef VMA_ALIGN_OF
      +
      4206  #define VMA_ALIGN_OF(type) (__alignof(type))
      +
      4207 #endif
      +
      4208 
      +
      4209 #ifndef VMA_SYSTEM_ALIGNED_MALLOC
      +
      4210  #define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) vma_aligned_alloc((alignment), (size))
      +
      4211 #endif
      +
      4212 
      +
      4213 #ifndef VMA_SYSTEM_ALIGNED_FREE
      +
      4214  // VMA_SYSTEM_FREE is the old name, but might have been defined by the user
      +
      4215  #if defined(VMA_SYSTEM_FREE)
      +
      4216  #define VMA_SYSTEM_ALIGNED_FREE(ptr) VMA_SYSTEM_FREE(ptr)
      +
      4217  #else
      +
      4218  #define VMA_SYSTEM_ALIGNED_FREE(ptr) vma_aligned_free(ptr)
      +
      4219  #endif
      +
      4220 #endif
      +
      4221 
      +
      4222 #ifndef VMA_MIN
      +
      4223  #define VMA_MIN(v1, v2) (std::min((v1), (v2)))
      +
      4224 #endif
      +
      4225 
      +
      4226 #ifndef VMA_MAX
      +
      4227  #define VMA_MAX(v1, v2) (std::max((v1), (v2)))
      +
      4228 #endif
      +
      4229 
      +
      4230 #ifndef VMA_SWAP
      +
      4231  #define VMA_SWAP(v1, v2) std::swap((v1), (v2))
      4232 #endif
      4233 
      -
      4234 #ifndef VMA_MIN
      -
      4235  #define VMA_MIN(v1, v2) (std::min((v1), (v2)))
      +
      4234 #ifndef VMA_SORT
      +
      4235  #define VMA_SORT(beg, end, cmp) std::sort(beg, end, cmp)
      4236 #endif
      4237 
      -
      4238 #ifndef VMA_MAX
      -
      4239  #define VMA_MAX(v1, v2) (std::max((v1), (v2)))
      -
      4240 #endif
      -
      4241 
      -
      4242 #ifndef VMA_SWAP
      -
      4243  #define VMA_SWAP(v1, v2) std::swap((v1), (v2))
      -
      4244 #endif
      -
      4245 
      -
      4246 #ifndef VMA_SORT
      -
      4247  #define VMA_SORT(beg, end, cmp) std::sort(beg, end, cmp)
      -
      4248 #endif
      -
      4249 
      -
      4250 #ifndef VMA_DEBUG_LOG
      -
      4251  #define VMA_DEBUG_LOG(format, ...)
      -
      4252  /*
      -
      4253  #define VMA_DEBUG_LOG(format, ...) do { \
      -
      4254  printf(format, __VA_ARGS__); \
      -
      4255  printf("\n"); \
      -
      4256  } while(false)
      -
      4257  */
      -
      4258 #endif
      -
      4259 
      -
      4260 // Define this macro to 1 to enable functions: vmaBuildStatsString, vmaFreeStatsString.
      -
      4261 #if VMA_STATS_STRING_ENABLED
      -
      4262  static inline void VmaUint32ToStr(char* outStr, size_t strLen, uint32_t num)
      -
      4263  {
      -
      4264  snprintf(outStr, strLen, "%u", static_cast<unsigned int>(num));
      -
      4265  }
      -
      4266  static inline void VmaUint64ToStr(char* outStr, size_t strLen, uint64_t num)
      -
      4267  {
      -
      4268  snprintf(outStr, strLen, "%llu", static_cast<unsigned long long>(num));
      -
      4269  }
      -
      4270  static inline void VmaPtrToStr(char* outStr, size_t strLen, const void* ptr)
      -
      4271  {
      -
      4272  snprintf(outStr, strLen, "%p", ptr);
      -
      4273  }
      -
      4274 #endif
      -
      4275 
      -
      4276 #ifndef VMA_MUTEX
      -
      4277  class VmaMutex
      -
      4278  {
      -
      4279  public:
      -
      4280  void Lock() { m_Mutex.lock(); }
      -
      4281  void Unlock() { m_Mutex.unlock(); }
      -
      4282  bool TryLock() { return m_Mutex.try_lock(); }
      -
      4283  private:
      -
      4284  std::mutex m_Mutex;
      -
      4285  };
      -
      4286  #define VMA_MUTEX VmaMutex
      -
      4287 #endif
      -
      4288 
      -
      4289 // Read-write mutex, where "read" is shared access, "write" is exclusive access.
      -
      4290 #ifndef VMA_RW_MUTEX
      -
      4291  #if VMA_USE_STL_SHARED_MUTEX
      -
      4292  // Use std::shared_mutex from C++17.
      -
      4293  #include <shared_mutex>
      -
      4294  class VmaRWMutex
      -
      4295  {
      -
      4296  public:
      -
      4297  void LockRead() { m_Mutex.lock_shared(); }
      -
      4298  void UnlockRead() { m_Mutex.unlock_shared(); }
      -
      4299  bool TryLockRead() { return m_Mutex.try_lock_shared(); }
      -
      4300  void LockWrite() { m_Mutex.lock(); }
      -
      4301  void UnlockWrite() { m_Mutex.unlock(); }
      -
      4302  bool TryLockWrite() { return m_Mutex.try_lock(); }
      -
      4303  private:
      -
      4304  std::shared_mutex m_Mutex;
      -
      4305  };
      -
      4306  #define VMA_RW_MUTEX VmaRWMutex
      -
      4307  #elif defined(_WIN32) && defined(WINVER) && WINVER >= 0x0600
      -
      4308  // Use SRWLOCK from WinAPI.
      -
      4309  // Minimum supported client = Windows Vista, server = Windows Server 2008.
      -
      4310  class VmaRWMutex
      -
      4311  {
      -
      4312  public:
      -
      4313  VmaRWMutex() { InitializeSRWLock(&m_Lock); }
      -
      4314  void LockRead() { AcquireSRWLockShared(&m_Lock); }
      -
      4315  void UnlockRead() { ReleaseSRWLockShared(&m_Lock); }
      -
      4316  bool TryLockRead() { return TryAcquireSRWLockShared(&m_Lock) != FALSE; }
      -
      4317  void LockWrite() { AcquireSRWLockExclusive(&m_Lock); }
      -
      4318  void UnlockWrite() { ReleaseSRWLockExclusive(&m_Lock); }
      -
      4319  bool TryLockWrite() { return TryAcquireSRWLockExclusive(&m_Lock) != FALSE; }
      -
      4320  private:
      -
      4321  SRWLOCK m_Lock;
      -
      4322  };
      -
      4323  #define VMA_RW_MUTEX VmaRWMutex
      -
      4324  #else
      -
      4325  // Less efficient fallback: Use normal mutex.
      -
      4326  class VmaRWMutex
      -
      4327  {
      -
      4328  public:
      -
      4329  void LockRead() { m_Mutex.Lock(); }
      -
      4330  void UnlockRead() { m_Mutex.Unlock(); }
      -
      4331  bool TryLockRead() { return m_Mutex.TryLock(); }
      -
      4332  void LockWrite() { m_Mutex.Lock(); }
      -
      4333  void UnlockWrite() { m_Mutex.Unlock(); }
      -
      4334  bool TryLockWrite() { return m_Mutex.TryLock(); }
      -
      4335  private:
      -
      4336  VMA_MUTEX m_Mutex;
      -
      4337  };
      -
      4338  #define VMA_RW_MUTEX VmaRWMutex
      -
      4339  #endif // #if VMA_USE_STL_SHARED_MUTEX
      -
      4340 #endif // #ifndef VMA_RW_MUTEX
      -
      4341 
      -
      4342 /*
      -
      4343 If providing your own implementation, you need to implement a subset of std::atomic.
      -
      4344 */
      -
      4345 #ifndef VMA_ATOMIC_UINT32
      -
      4346  #include <atomic>
      -
      4347  #define VMA_ATOMIC_UINT32 std::atomic<uint32_t>
      -
      4348 #endif
      -
      4349 
      -
      4350 #ifndef VMA_ATOMIC_UINT64
      -
      4351  #include <atomic>
      -
      4352  #define VMA_ATOMIC_UINT64 std::atomic<uint64_t>
      -
      4353 #endif
      -
      4354 
      -
      4355 #ifndef VMA_DEBUG_ALWAYS_DEDICATED_MEMORY
      -
      4360  #define VMA_DEBUG_ALWAYS_DEDICATED_MEMORY (0)
      -
      4361 #endif
      -
      4362 
      -
      4363 #ifndef VMA_DEBUG_ALIGNMENT
      -
      4368  #define VMA_DEBUG_ALIGNMENT (1)
      -
      4369 #endif
      -
      4370 
      -
      4371 #ifndef VMA_DEBUG_MARGIN
      -
      4376  #define VMA_DEBUG_MARGIN (0)
      -
      4377 #endif
      -
      4378 
      -
      4379 #ifndef VMA_DEBUG_INITIALIZE_ALLOCATIONS
      -
      4384  #define VMA_DEBUG_INITIALIZE_ALLOCATIONS (0)
      -
      4385 #endif
      -
      4386 
      -
      4387 #ifndef VMA_DEBUG_DETECT_CORRUPTION
      -
      4393  #define VMA_DEBUG_DETECT_CORRUPTION (0)
      -
      4394 #endif
      -
      4395 
      -
      4396 #ifndef VMA_DEBUG_GLOBAL_MUTEX
      -
      4401  #define VMA_DEBUG_GLOBAL_MUTEX (0)
      -
      4402 #endif
      -
      4403 
      -
      4404 #ifndef VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY
      -
      4409  #define VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY (1)
      -
      4410 #endif
      -
      4411 
      -
      4412 #ifndef VMA_SMALL_HEAP_MAX_SIZE
      -
      4414  #define VMA_SMALL_HEAP_MAX_SIZE (1024ull * 1024 * 1024)
      -
      4415 #endif
      -
      4416 
      -
      4417 #ifndef VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE
      -
      4419  #define VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE (256ull * 1024 * 1024)
      -
      4420 #endif
      -
      4421 
      -
      4422 #ifndef VMA_CLASS_NO_COPY
      -
      4423  #define VMA_CLASS_NO_COPY(className) \
      -
      4424  private: \
      -
      4425  className(const className&) = delete; \
      -
      4426  className& operator=(const className&) = delete;
      -
      4427 #endif
      -
      4428 
      -
      4429 static const uint32_t VMA_FRAME_INDEX_LOST = UINT32_MAX;
      -
      4430 
      -
      4431 // Decimal 2139416166, float NaN, little-endian binary 66 E6 84 7F.
      -
      4432 static const uint32_t VMA_CORRUPTION_DETECTION_MAGIC_VALUE = 0x7F84E666;
      -
      4433 
      -
      4434 static const uint8_t VMA_ALLOCATION_FILL_PATTERN_CREATED = 0xDC;
      -
      4435 static const uint8_t VMA_ALLOCATION_FILL_PATTERN_DESTROYED = 0xEF;
      +
      4238 #ifndef VMA_DEBUG_LOG
      +
      4239  #define VMA_DEBUG_LOG(format, ...)
      +
      4240  /*
      +
      4241  #define VMA_DEBUG_LOG(format, ...) do { \
      +
      4242  printf(format, __VA_ARGS__); \
      +
      4243  printf("\n"); \
      +
      4244  } while(false)
      +
      4245  */
      +
      4246 #endif
      +
      4247 
      +
      4248 // Define this macro to 1 to enable functions: vmaBuildStatsString, vmaFreeStatsString.
      +
      4249 #if VMA_STATS_STRING_ENABLED
      +
      4250  static inline void VmaUint32ToStr(char* outStr, size_t strLen, uint32_t num)
      +
      4251  {
      +
      4252  snprintf(outStr, strLen, "%u", static_cast<unsigned int>(num));
      +
      4253  }
      +
      4254  static inline void VmaUint64ToStr(char* outStr, size_t strLen, uint64_t num)
      +
      4255  {
      +
      4256  snprintf(outStr, strLen, "%llu", static_cast<unsigned long long>(num));
      +
      4257  }
      +
      4258  static inline void VmaPtrToStr(char* outStr, size_t strLen, const void* ptr)
      +
      4259  {
      +
      4260  snprintf(outStr, strLen, "%p", ptr);
      +
      4261  }
      +
      4262 #endif
      +
      4263 
      +
      4264 #ifndef VMA_MUTEX
      +
      4265  class VmaMutex
      +
      4266  {
      +
      4267  public:
      +
      4268  void Lock() { m_Mutex.lock(); }
      +
      4269  void Unlock() { m_Mutex.unlock(); }
      +
      4270  bool TryLock() { return m_Mutex.try_lock(); }
      +
      4271  private:
      +
      4272  std::mutex m_Mutex;
      +
      4273  };
      +
      4274  #define VMA_MUTEX VmaMutex
      +
      4275 #endif
      +
      4276 
      +
      4277 // Read-write mutex, where "read" is shared access, "write" is exclusive access.
      +
      4278 #ifndef VMA_RW_MUTEX
      +
      4279  #if VMA_USE_STL_SHARED_MUTEX
      +
      4280  // Use std::shared_mutex from C++17.
      +
      4281  #include <shared_mutex>
      +
      4282  class VmaRWMutex
      +
      4283  {
      +
      4284  public:
      +
      4285  void LockRead() { m_Mutex.lock_shared(); }
      +
      4286  void UnlockRead() { m_Mutex.unlock_shared(); }
      +
      4287  bool TryLockRead() { return m_Mutex.try_lock_shared(); }
      +
      4288  void LockWrite() { m_Mutex.lock(); }
      +
      4289  void UnlockWrite() { m_Mutex.unlock(); }
      +
      4290  bool TryLockWrite() { return m_Mutex.try_lock(); }
      +
      4291  private:
      +
      4292  std::shared_mutex m_Mutex;
      +
      4293  };
      +
      4294  #define VMA_RW_MUTEX VmaRWMutex
      +
      4295  #elif defined(_WIN32) && defined(WINVER) && WINVER >= 0x0600
      +
      4296  // Use SRWLOCK from WinAPI.
      +
      4297  // Minimum supported client = Windows Vista, server = Windows Server 2008.
      +
      4298  class VmaRWMutex
      +
      4299  {
      +
      4300  public:
      +
      4301  VmaRWMutex() { InitializeSRWLock(&m_Lock); }
      +
      4302  void LockRead() { AcquireSRWLockShared(&m_Lock); }
      +
      4303  void UnlockRead() { ReleaseSRWLockShared(&m_Lock); }
      +
      4304  bool TryLockRead() { return TryAcquireSRWLockShared(&m_Lock) != FALSE; }
      +
      4305  void LockWrite() { AcquireSRWLockExclusive(&m_Lock); }
      +
      4306  void UnlockWrite() { ReleaseSRWLockExclusive(&m_Lock); }
      +
      4307  bool TryLockWrite() { return TryAcquireSRWLockExclusive(&m_Lock) != FALSE; }
      +
      4308  private:
      +
      4309  SRWLOCK m_Lock;
      +
      4310  };
      +
      4311  #define VMA_RW_MUTEX VmaRWMutex
      +
      4312  #else
      +
      4313  // Less efficient fallback: Use normal mutex.
      +
      4314  class VmaRWMutex
      +
      4315  {
      +
      4316  public:
      +
      4317  void LockRead() { m_Mutex.Lock(); }
      +
      4318  void UnlockRead() { m_Mutex.Unlock(); }
      +
      4319  bool TryLockRead() { return m_Mutex.TryLock(); }
      +
      4320  void LockWrite() { m_Mutex.Lock(); }
      +
      4321  void UnlockWrite() { m_Mutex.Unlock(); }
      +
      4322  bool TryLockWrite() { return m_Mutex.TryLock(); }
      +
      4323  private:
      +
      4324  VMA_MUTEX m_Mutex;
      +
      4325  };
      +
      4326  #define VMA_RW_MUTEX VmaRWMutex
      +
      4327  #endif // #if VMA_USE_STL_SHARED_MUTEX
      +
      4328 #endif // #ifndef VMA_RW_MUTEX
      +
      4329 
      +
      4330 /*
      +
      4331 If providing your own implementation, you need to implement a subset of std::atomic.
      +
      4332 */
      +
      4333 #ifndef VMA_ATOMIC_UINT32
      +
      4334  #include <atomic>
      +
      4335  #define VMA_ATOMIC_UINT32 std::atomic<uint32_t>
      +
      4336 #endif
      +
      4337 
      +
      4338 #ifndef VMA_ATOMIC_UINT64
      +
      4339  #include <atomic>
      +
      4340  #define VMA_ATOMIC_UINT64 std::atomic<uint64_t>
      +
      4341 #endif
      +
      4342 
      +
      4343 #ifndef VMA_DEBUG_ALWAYS_DEDICATED_MEMORY
      +
      4348  #define VMA_DEBUG_ALWAYS_DEDICATED_MEMORY (0)
      +
      4349 #endif
      +
      4350 
      +
      4351 #ifndef VMA_DEBUG_ALIGNMENT
      +
      4356  #define VMA_DEBUG_ALIGNMENT (1)
      +
      4357 #endif
      +
      4358 
      +
      4359 #ifndef VMA_DEBUG_MARGIN
      +
      4364  #define VMA_DEBUG_MARGIN (0)
      +
      4365 #endif
      +
      4366 
      +
      4367 #ifndef VMA_DEBUG_INITIALIZE_ALLOCATIONS
      +
      4372  #define VMA_DEBUG_INITIALIZE_ALLOCATIONS (0)
      +
      4373 #endif
      +
      4374 
      +
      4375 #ifndef VMA_DEBUG_DETECT_CORRUPTION
      +
      4381  #define VMA_DEBUG_DETECT_CORRUPTION (0)
      +
      4382 #endif
      +
      4383 
      +
      4384 #ifndef VMA_DEBUG_GLOBAL_MUTEX
      +
      4389  #define VMA_DEBUG_GLOBAL_MUTEX (0)
      +
      4390 #endif
      +
      4391 
      +
      4392 #ifndef VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY
      +
      4397  #define VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY (1)
      +
      4398 #endif
      +
      4399 
      +
      4400 #ifndef VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT
      +
      4401  /*
      +
      4402  Set this to 1 to make VMA never exceed VkPhysicalDeviceLimits::maxMemoryAllocationCount
      +
      4403  and return error instead of leaving up to Vulkan implementation what to do in such cases.
      +
      4404  */
      +
      4405  #define VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT (0)
      +
      4406 #endif
      +
      4407 
      +
      4408 #ifndef VMA_SMALL_HEAP_MAX_SIZE
      +
      4410  #define VMA_SMALL_HEAP_MAX_SIZE (1024ull * 1024 * 1024)
      +
      4411 #endif
      +
      4412 
      +
      4413 #ifndef VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE
      +
      4415  #define VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE (256ull * 1024 * 1024)
      +
      4416 #endif
      +
      4417 
      +
      4418 #ifndef VMA_CLASS_NO_COPY
      +
      4419  #define VMA_CLASS_NO_COPY(className) \
      +
      4420  private: \
      +
      4421  className(const className&) = delete; \
      +
      4422  className& operator=(const className&) = delete;
      +
      4423 #endif
      +
      4424 
      +
      4425 static const uint32_t VMA_FRAME_INDEX_LOST = UINT32_MAX;
      +
      4426 
      +
      4427 // Decimal 2139416166, float NaN, little-endian binary 66 E6 84 7F.
      +
      4428 static const uint32_t VMA_CORRUPTION_DETECTION_MAGIC_VALUE = 0x7F84E666;
      +
      4429 
      +
      4430 static const uint8_t VMA_ALLOCATION_FILL_PATTERN_CREATED = 0xDC;
      +
      4431 static const uint8_t VMA_ALLOCATION_FILL_PATTERN_DESTROYED = 0xEF;
      +
      4432 
      +
      4433 /*******************************************************************************
      +
      4434 END OF CONFIGURATION
      +
      4435 */
      4436 
      -
      4437 /*******************************************************************************
      -
      4438 END OF CONFIGURATION
      -
      4439 */
      -
      4440 
      -
      4441 // # Copy of some Vulkan definitions so we don't need to check their existence just to handle few constants.
      +
      4437 // # Copy of some Vulkan definitions so we don't need to check their existence just to handle few constants.
      +
      4438 
      +
      4439 static const uint32_t VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY = 0x00000040;
      +
      4440 static const uint32_t VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY = 0x00000080;
      +
      4441 static const uint32_t VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY = 0x00020000;
      4442 
      -
      4443 static const uint32_t VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY = 0x00000040;
      -
      4444 static const uint32_t VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY = 0x00000080;
      -
      4445 static const uint32_t VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY = 0x00020000;
      -
      4446 
      -
      4447 static const uint32_t VMA_ALLOCATION_INTERNAL_STRATEGY_MIN_OFFSET = 0x10000000u;
      -
      4448 
      -
      4449 static VkAllocationCallbacks VmaEmptyAllocationCallbacks = {
      -
      4450  VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL };
      -
      4451 
      -
      4452 // Returns number of bits set to 1 in (v).
      -
      4453 static inline uint32_t VmaCountBitsSet(uint32_t v)
      -
      4454 {
      -
      4455  uint32_t c = v - ((v >> 1) & 0x55555555);
      -
      4456  c = ((c >> 2) & 0x33333333) + (c & 0x33333333);
      -
      4457  c = ((c >> 4) + c) & 0x0F0F0F0F;
      -
      4458  c = ((c >> 8) + c) & 0x00FF00FF;
      -
      4459  c = ((c >> 16) + c) & 0x0000FFFF;
      -
      4460  return c;
      -
      4461 }
      -
      4462 
      -
      4463 /*
      -
      4464 Returns true if given number is a power of two.
      -
      4465 T must be unsigned integer number or signed integer but always nonnegative.
      -
      4466 For 0 returns true.
      -
      4467 */
      -
      4468 template <typename T>
      -
      4469 inline bool VmaIsPow2(T x)
      -
      4470 {
      -
      4471  return (x & (x-1)) == 0;
      -
      4472 }
      -
      4473 
      -
      4474 // Aligns given value up to nearest multiply of align value. For example: VmaAlignUp(11, 8) = 16.
      -
      4475 // Use types like uint32_t, uint64_t as T.
      -
      4476 template <typename T>
      -
      4477 static inline T VmaAlignUp(T val, T alignment)
      -
      4478 {
      -
      4479  VMA_HEAVY_ASSERT(VmaIsPow2(alignment));
      -
      4480  return (val + alignment - 1) & ~(alignment - 1);
      -
      4481 }
      -
      4482 // Aligns given value down to nearest multiply of align value. For example: VmaAlignUp(11, 8) = 8.
      -
      4483 // Use types like uint32_t, uint64_t as T.
      -
      4484 template <typename T>
      -
      4485 static inline T VmaAlignDown(T val, T alignment)
      -
      4486 {
      -
      4487  VMA_HEAVY_ASSERT(VmaIsPow2(alignment));
      -
      4488  return val & ~(alignment - 1);
      -
      4489 }
      -
      4490 
      -
      4491 // Division with mathematical rounding to nearest number.
      -
      4492 template <typename T>
      -
      4493 static inline T VmaRoundDiv(T x, T y)
      -
      4494 {
      -
      4495  return (x + (y / (T)2)) / y;
      -
      4496 }
      -
      4497 
      -
      4498 // Returns smallest power of 2 greater or equal to v.
      -
      4499 static inline uint32_t VmaNextPow2(uint32_t v)
      -
      4500 {
      -
      4501  v--;
      -
      4502  v |= v >> 1;
      -
      4503  v |= v >> 2;
      -
      4504  v |= v >> 4;
      -
      4505  v |= v >> 8;
      -
      4506  v |= v >> 16;
      -
      4507  v++;
      -
      4508  return v;
      -
      4509 }
      -
      4510 static inline uint64_t VmaNextPow2(uint64_t v)
      -
      4511 {
      -
      4512  v--;
      -
      4513  v |= v >> 1;
      -
      4514  v |= v >> 2;
      -
      4515  v |= v >> 4;
      -
      4516  v |= v >> 8;
      -
      4517  v |= v >> 16;
      -
      4518  v |= v >> 32;
      -
      4519  v++;
      -
      4520  return v;
      -
      4521 }
      -
      4522 
      -
      4523 // Returns largest power of 2 less or equal to v.
      -
      4524 static inline uint32_t VmaPrevPow2(uint32_t v)
      -
      4525 {
      -
      4526  v |= v >> 1;
      -
      4527  v |= v >> 2;
      -
      4528  v |= v >> 4;
      -
      4529  v |= v >> 8;
      -
      4530  v |= v >> 16;
      -
      4531  v = v ^ (v >> 1);
      -
      4532  return v;
      -
      4533 }
      -
      4534 static inline uint64_t VmaPrevPow2(uint64_t v)
      -
      4535 {
      -
      4536  v |= v >> 1;
      -
      4537  v |= v >> 2;
      -
      4538  v |= v >> 4;
      -
      4539  v |= v >> 8;
      -
      4540  v |= v >> 16;
      -
      4541  v |= v >> 32;
      -
      4542  v = v ^ (v >> 1);
      -
      4543  return v;
      -
      4544 }
      -
      4545 
      -
      4546 static inline bool VmaStrIsEmpty(const char* pStr)
      -
      4547 {
      -
      4548  return pStr == VMA_NULL || *pStr == '\0';
      -
      4549 }
      -
      4550 
      -
      4551 #if VMA_STATS_STRING_ENABLED
      -
      4552 
      -
      4553 static const char* VmaAlgorithmToStr(uint32_t algorithm)
      -
      4554 {
      -
      4555  switch(algorithm)
      -
      4556  {
      - -
      4558  return "Linear";
      - -
      4560  return "Buddy";
      -
      4561  case 0:
      -
      4562  return "Default";
      -
      4563  default:
      -
      4564  VMA_ASSERT(0);
      -
      4565  return "";
      -
      4566  }
      -
      4567 }
      +
      4443 static const uint32_t VMA_ALLOCATION_INTERNAL_STRATEGY_MIN_OFFSET = 0x10000000u;
      +
      4444 
      +
      4445 static VkAllocationCallbacks VmaEmptyAllocationCallbacks = {
      +
      4446  VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL };
      +
      4447 
      +
      4448 // Returns number of bits set to 1 in (v).
      +
      4449 static inline uint32_t VmaCountBitsSet(uint32_t v)
      +
      4450 {
      +
      4451  uint32_t c = v - ((v >> 1) & 0x55555555);
      +
      4452  c = ((c >> 2) & 0x33333333) + (c & 0x33333333);
      +
      4453  c = ((c >> 4) + c) & 0x0F0F0F0F;
      +
      4454  c = ((c >> 8) + c) & 0x00FF00FF;
      +
      4455  c = ((c >> 16) + c) & 0x0000FFFF;
      +
      4456  return c;
      +
      4457 }
      +
      4458 
      +
      4459 /*
      +
      4460 Returns true if given number is a power of two.
      +
      4461 T must be unsigned integer number or signed integer but always nonnegative.
      +
      4462 For 0 returns true.
      +
      4463 */
      +
      4464 template <typename T>
      +
      4465 inline bool VmaIsPow2(T x)
      +
      4466 {
      +
      4467  return (x & (x-1)) == 0;
      +
      4468 }
      +
      4469 
      +
      4470 // Aligns given value up to nearest multiply of align value. For example: VmaAlignUp(11, 8) = 16.
      +
      4471 // Use types like uint32_t, uint64_t as T.
      +
      4472 template <typename T>
      +
      4473 static inline T VmaAlignUp(T val, T alignment)
      +
      4474 {
      +
      4475  VMA_HEAVY_ASSERT(VmaIsPow2(alignment));
      +
      4476  return (val + alignment - 1) & ~(alignment - 1);
      +
      4477 }
      +
      4478 // Aligns given value down to nearest multiply of align value. For example: VmaAlignUp(11, 8) = 8.
      +
      4479 // Use types like uint32_t, uint64_t as T.
      +
      4480 template <typename T>
      +
      4481 static inline T VmaAlignDown(T val, T alignment)
      +
      4482 {
      +
      4483  VMA_HEAVY_ASSERT(VmaIsPow2(alignment));
      +
      4484  return val & ~(alignment - 1);
      +
      4485 }
      +
      4486 
      +
      4487 // Division with mathematical rounding to nearest number.
      +
      4488 template <typename T>
      +
      4489 static inline T VmaRoundDiv(T x, T y)
      +
      4490 {
      +
      4491  return (x + (y / (T)2)) / y;
      +
      4492 }
      +
      4493 
      +
      4494 // Returns smallest power of 2 greater or equal to v.
      +
      4495 static inline uint32_t VmaNextPow2(uint32_t v)
      +
      4496 {
      +
      4497  v--;
      +
      4498  v |= v >> 1;
      +
      4499  v |= v >> 2;
      +
      4500  v |= v >> 4;
      +
      4501  v |= v >> 8;
      +
      4502  v |= v >> 16;
      +
      4503  v++;
      +
      4504  return v;
      +
      4505 }
      +
      4506 static inline uint64_t VmaNextPow2(uint64_t v)
      +
      4507 {
      +
      4508  v--;
      +
      4509  v |= v >> 1;
      +
      4510  v |= v >> 2;
      +
      4511  v |= v >> 4;
      +
      4512  v |= v >> 8;
      +
      4513  v |= v >> 16;
      +
      4514  v |= v >> 32;
      +
      4515  v++;
      +
      4516  return v;
      +
      4517 }
      +
      4518 
      +
      4519 // Returns largest power of 2 less or equal to v.
      +
      4520 static inline uint32_t VmaPrevPow2(uint32_t v)
      +
      4521 {
      +
      4522  v |= v >> 1;
      +
      4523  v |= v >> 2;
      +
      4524  v |= v >> 4;
      +
      4525  v |= v >> 8;
      +
      4526  v |= v >> 16;
      +
      4527  v = v ^ (v >> 1);
      +
      4528  return v;
      +
      4529 }
      +
      4530 static inline uint64_t VmaPrevPow2(uint64_t v)
      +
      4531 {
      +
      4532  v |= v >> 1;
      +
      4533  v |= v >> 2;
      +
      4534  v |= v >> 4;
      +
      4535  v |= v >> 8;
      +
      4536  v |= v >> 16;
      +
      4537  v |= v >> 32;
      +
      4538  v = v ^ (v >> 1);
      +
      4539  return v;
      +
      4540 }
      +
      4541 
      +
      4542 static inline bool VmaStrIsEmpty(const char* pStr)
      +
      4543 {
      +
      4544  return pStr == VMA_NULL || *pStr == '\0';
      +
      4545 }
      +
      4546 
      +
      4547 #if VMA_STATS_STRING_ENABLED
      +
      4548 
      +
      4549 static const char* VmaAlgorithmToStr(uint32_t algorithm)
      +
      4550 {
      +
      4551  switch(algorithm)
      +
      4552  {
      + +
      4554  return "Linear";
      + +
      4556  return "Buddy";
      +
      4557  case 0:
      +
      4558  return "Default";
      +
      4559  default:
      +
      4560  VMA_ASSERT(0);
      +
      4561  return "";
      +
      4562  }
      +
      4563 }
      +
      4564 
      +
      4565 #endif // #if VMA_STATS_STRING_ENABLED
      +
      4566 
      +
      4567 #ifndef VMA_SORT
      4568 
      -
      4569 #endif // #if VMA_STATS_STRING_ENABLED
      -
      4570 
      -
      4571 #ifndef VMA_SORT
      -
      4572 
      -
      4573 template<typename Iterator, typename Compare>
      -
      4574 Iterator VmaQuickSortPartition(Iterator beg, Iterator end, Compare cmp)
      -
      4575 {
      -
      4576  Iterator centerValue = end; --centerValue;
      -
      4577  Iterator insertIndex = beg;
      -
      4578  for(Iterator memTypeIndex = beg; memTypeIndex < centerValue; ++memTypeIndex)
      -
      4579  {
      -
      4580  if(cmp(*memTypeIndex, *centerValue))
      -
      4581  {
      -
      4582  if(insertIndex != memTypeIndex)
      -
      4583  {
      -
      4584  VMA_SWAP(*memTypeIndex, *insertIndex);
      -
      4585  }
      -
      4586  ++insertIndex;
      -
      4587  }
      +
      4569 template<typename Iterator, typename Compare>
      +
      4570 Iterator VmaQuickSortPartition(Iterator beg, Iterator end, Compare cmp)
      +
      4571 {
      +
      4572  Iterator centerValue = end; --centerValue;
      +
      4573  Iterator insertIndex = beg;
      +
      4574  for(Iterator memTypeIndex = beg; memTypeIndex < centerValue; ++memTypeIndex)
      +
      4575  {
      +
      4576  if(cmp(*memTypeIndex, *centerValue))
      +
      4577  {
      +
      4578  if(insertIndex != memTypeIndex)
      +
      4579  {
      +
      4580  VMA_SWAP(*memTypeIndex, *insertIndex);
      +
      4581  }
      +
      4582  ++insertIndex;
      +
      4583  }
      +
      4584  }
      +
      4585  if(insertIndex != centerValue)
      +
      4586  {
      +
      4587  VMA_SWAP(*insertIndex, *centerValue);
      4588  }
      -
      4589  if(insertIndex != centerValue)
      -
      4590  {
      -
      4591  VMA_SWAP(*insertIndex, *centerValue);
      -
      4592  }
      -
      4593  return insertIndex;
      -
      4594 }
      -
      4595 
      -
      4596 template<typename Iterator, typename Compare>
      -
      4597 void VmaQuickSort(Iterator beg, Iterator end, Compare cmp)
      -
      4598 {
      -
      4599  if(beg < end)
      -
      4600  {
      -
      4601  Iterator it = VmaQuickSortPartition<Iterator, Compare>(beg, end, cmp);
      -
      4602  VmaQuickSort<Iterator, Compare>(beg, it, cmp);
      -
      4603  VmaQuickSort<Iterator, Compare>(it + 1, end, cmp);
      -
      4604  }
      -
      4605 }
      +
      4589  return insertIndex;
      +
      4590 }
      +
      4591 
      +
      4592 template<typename Iterator, typename Compare>
      +
      4593 void VmaQuickSort(Iterator beg, Iterator end, Compare cmp)
      +
      4594 {
      +
      4595  if(beg < end)
      +
      4596  {
      +
      4597  Iterator it = VmaQuickSortPartition<Iterator, Compare>(beg, end, cmp);
      +
      4598  VmaQuickSort<Iterator, Compare>(beg, it, cmp);
      +
      4599  VmaQuickSort<Iterator, Compare>(it + 1, end, cmp);
      +
      4600  }
      +
      4601 }
      +
      4602 
      +
      4603 #define VMA_SORT(beg, end, cmp) VmaQuickSort(beg, end, cmp)
      +
      4604 
      +
      4605 #endif // #ifndef VMA_SORT
      4606 
      -
      4607 #define VMA_SORT(beg, end, cmp) VmaQuickSort(beg, end, cmp)
      -
      4608 
      -
      4609 #endif // #ifndef VMA_SORT
      -
      4610 
      -
      4611 /*
      -
      4612 Returns true if two memory blocks occupy overlapping pages.
      -
      4613 ResourceA must be in less memory offset than ResourceB.
      -
      4614 
      -
      4615 Algorithm is based on "Vulkan 1.0.39 - A Specification (with all registered Vulkan extensions)"
      -
      4616 chapter 11.6 "Resource Memory Association", paragraph "Buffer-Image Granularity".
      -
      4617 */
      -
      4618 static inline bool VmaBlocksOnSamePage(
      -
      4619  VkDeviceSize resourceAOffset,
      -
      4620  VkDeviceSize resourceASize,
      -
      4621  VkDeviceSize resourceBOffset,
      -
      4622  VkDeviceSize pageSize)
      -
      4623 {
      -
      4624  VMA_ASSERT(resourceAOffset + resourceASize <= resourceBOffset && resourceASize > 0 && pageSize > 0);
      -
      4625  VkDeviceSize resourceAEnd = resourceAOffset + resourceASize - 1;
      -
      4626  VkDeviceSize resourceAEndPage = resourceAEnd & ~(pageSize - 1);
      -
      4627  VkDeviceSize resourceBStart = resourceBOffset;
      -
      4628  VkDeviceSize resourceBStartPage = resourceBStart & ~(pageSize - 1);
      -
      4629  return resourceAEndPage == resourceBStartPage;
      -
      4630 }
      -
      4631 
      -
      4632 enum VmaSuballocationType
      -
      4633 {
      -
      4634  VMA_SUBALLOCATION_TYPE_FREE = 0,
      -
      4635  VMA_SUBALLOCATION_TYPE_UNKNOWN = 1,
      -
      4636  VMA_SUBALLOCATION_TYPE_BUFFER = 2,
      -
      4637  VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN = 3,
      -
      4638  VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR = 4,
      -
      4639  VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL = 5,
      -
      4640  VMA_SUBALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF
      -
      4641 };
      -
      4642 
      -
      4643 /*
      -
      4644 Returns true if given suballocation types could conflict and must respect
      -
      4645 VkPhysicalDeviceLimits::bufferImageGranularity. They conflict if one is buffer
      -
      4646 or linear image and another one is optimal image. If type is unknown, behave
      -
      4647 conservatively.
      -
      4648 */
      -
      4649 static inline bool VmaIsBufferImageGranularityConflict(
      -
      4650  VmaSuballocationType suballocType1,
      -
      4651  VmaSuballocationType suballocType2)
      -
      4652 {
      -
      4653  if(suballocType1 > suballocType2)
      -
      4654  {
      -
      4655  VMA_SWAP(suballocType1, suballocType2);
      -
      4656  }
      -
      4657 
      -
      4658  switch(suballocType1)
      -
      4659  {
      -
      4660  case VMA_SUBALLOCATION_TYPE_FREE:
      -
      4661  return false;
      -
      4662  case VMA_SUBALLOCATION_TYPE_UNKNOWN:
      -
      4663  return true;
      -
      4664  case VMA_SUBALLOCATION_TYPE_BUFFER:
      +
      4607 /*
      +
      4608 Returns true if two memory blocks occupy overlapping pages.
      +
      4609 ResourceA must be in less memory offset than ResourceB.
      +
      4610 
      +
      4611 Algorithm is based on "Vulkan 1.0.39 - A Specification (with all registered Vulkan extensions)"
      +
      4612 chapter 11.6 "Resource Memory Association", paragraph "Buffer-Image Granularity".
      +
      4613 */
      +
      4614 static inline bool VmaBlocksOnSamePage(
      +
      4615  VkDeviceSize resourceAOffset,
      +
      4616  VkDeviceSize resourceASize,
      +
      4617  VkDeviceSize resourceBOffset,
      +
      4618  VkDeviceSize pageSize)
      +
      4619 {
      +
      4620  VMA_ASSERT(resourceAOffset + resourceASize <= resourceBOffset && resourceASize > 0 && pageSize > 0);
      +
      4621  VkDeviceSize resourceAEnd = resourceAOffset + resourceASize - 1;
      +
      4622  VkDeviceSize resourceAEndPage = resourceAEnd & ~(pageSize - 1);
      +
      4623  VkDeviceSize resourceBStart = resourceBOffset;
      +
      4624  VkDeviceSize resourceBStartPage = resourceBStart & ~(pageSize - 1);
      +
      4625  return resourceAEndPage == resourceBStartPage;
      +
      4626 }
      +
      4627 
      +
      4628 enum VmaSuballocationType
      +
      4629 {
      +
      4630  VMA_SUBALLOCATION_TYPE_FREE = 0,
      +
      4631  VMA_SUBALLOCATION_TYPE_UNKNOWN = 1,
      +
      4632  VMA_SUBALLOCATION_TYPE_BUFFER = 2,
      +
      4633  VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN = 3,
      +
      4634  VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR = 4,
      +
      4635  VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL = 5,
      +
      4636  VMA_SUBALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF
      +
      4637 };
      +
      4638 
      +
      4639 /*
      +
      4640 Returns true if given suballocation types could conflict and must respect
      +
      4641 VkPhysicalDeviceLimits::bufferImageGranularity. They conflict if one is buffer
      +
      4642 or linear image and another one is optimal image. If type is unknown, behave
      +
      4643 conservatively.
      +
      4644 */
      +
      4645 static inline bool VmaIsBufferImageGranularityConflict(
      +
      4646  VmaSuballocationType suballocType1,
      +
      4647  VmaSuballocationType suballocType2)
      +
      4648 {
      +
      4649  if(suballocType1 > suballocType2)
      +
      4650  {
      +
      4651  VMA_SWAP(suballocType1, suballocType2);
      +
      4652  }
      +
      4653 
      +
      4654  switch(suballocType1)
      +
      4655  {
      +
      4656  case VMA_SUBALLOCATION_TYPE_FREE:
      +
      4657  return false;
      +
      4658  case VMA_SUBALLOCATION_TYPE_UNKNOWN:
      +
      4659  return true;
      +
      4660  case VMA_SUBALLOCATION_TYPE_BUFFER:
      +
      4661  return
      +
      4662  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN ||
      +
      4663  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
      +
      4664  case VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN:
      4665  return
      4666  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN ||
      -
      4667  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
      -
      4668  case VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN:
      -
      4669  return
      -
      4670  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN ||
      -
      4671  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR ||
      -
      4672  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
      -
      4673  case VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR:
      -
      4674  return
      -
      4675  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
      -
      4676  case VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL:
      -
      4677  return false;
      -
      4678  default:
      -
      4679  VMA_ASSERT(0);
      -
      4680  return true;
      -
      4681  }
      -
      4682 }
      -
      4683 
      -
      4684 static void VmaWriteMagicValue(void* pData, VkDeviceSize offset)
      -
      4685 {
      -
      4686 #if VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_DETECT_CORRUPTION
      -
      4687  uint32_t* pDst = (uint32_t*)((char*)pData + offset);
      -
      4688  const size_t numberCount = VMA_DEBUG_MARGIN / sizeof(uint32_t);
      -
      4689  for(size_t i = 0; i < numberCount; ++i, ++pDst)
      -
      4690  {
      -
      4691  *pDst = VMA_CORRUPTION_DETECTION_MAGIC_VALUE;
      -
      4692  }
      -
      4693 #else
      -
      4694  // no-op
      -
      4695 #endif
      -
      4696 }
      -
      4697 
      -
      4698 static bool VmaValidateMagicValue(const void* pData, VkDeviceSize offset)
      -
      4699 {
      -
      4700 #if VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_DETECT_CORRUPTION
      -
      4701  const uint32_t* pSrc = (const uint32_t*)((const char*)pData + offset);
      -
      4702  const size_t numberCount = VMA_DEBUG_MARGIN / sizeof(uint32_t);
      -
      4703  for(size_t i = 0; i < numberCount; ++i, ++pSrc)
      -
      4704  {
      -
      4705  if(*pSrc != VMA_CORRUPTION_DETECTION_MAGIC_VALUE)
      -
      4706  {
      -
      4707  return false;
      -
      4708  }
      -
      4709  }
      -
      4710 #endif
      -
      4711  return true;
      -
      4712 }
      -
      4713 
      -
      4714 /*
      -
      4715 Fills structure with parameters of an example buffer to be used for transfers
      -
      4716 during GPU memory defragmentation.
      -
      4717 */
      -
      4718 static void VmaFillGpuDefragmentationBufferCreateInfo(VkBufferCreateInfo& outBufCreateInfo)
      -
      4719 {
      -
      4720  memset(&outBufCreateInfo, 0, sizeof(outBufCreateInfo));
      -
      4721  outBufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
      -
      4722  outBufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
      -
      4723  outBufCreateInfo.size = (VkDeviceSize)VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE; // Example size.
      -
      4724 }
      -
      4725 
      -
      4726 // Helper RAII class to lock a mutex in constructor and unlock it in destructor (at the end of scope).
      -
      4727 struct VmaMutexLock
      -
      4728 {
      -
      4729  VMA_CLASS_NO_COPY(VmaMutexLock)
      -
      4730 public:
      -
      4731  VmaMutexLock(VMA_MUTEX& mutex, bool useMutex = true) :
      -
      4732  m_pMutex(useMutex ? &mutex : VMA_NULL)
      -
      4733  { if(m_pMutex) { m_pMutex->Lock(); } }
      -
      4734  ~VmaMutexLock()
      -
      4735  { if(m_pMutex) { m_pMutex->Unlock(); } }
      -
      4736 private:
      -
      4737  VMA_MUTEX* m_pMutex;
      -
      4738 };
      -
      4739 
      -
      4740 // Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for reading.
      -
      4741 struct VmaMutexLockRead
      -
      4742 {
      -
      4743  VMA_CLASS_NO_COPY(VmaMutexLockRead)
      -
      4744 public:
      -
      4745  VmaMutexLockRead(VMA_RW_MUTEX& mutex, bool useMutex) :
      -
      4746  m_pMutex(useMutex ? &mutex : VMA_NULL)
      -
      4747  { if(m_pMutex) { m_pMutex->LockRead(); } }
      -
      4748  ~VmaMutexLockRead() { if(m_pMutex) { m_pMutex->UnlockRead(); } }
      -
      4749 private:
      -
      4750  VMA_RW_MUTEX* m_pMutex;
      -
      4751 };
      -
      4752 
      -
      4753 // Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for writing.
      -
      4754 struct VmaMutexLockWrite
      -
      4755 {
      -
      4756  VMA_CLASS_NO_COPY(VmaMutexLockWrite)
      -
      4757 public:
      -
      4758  VmaMutexLockWrite(VMA_RW_MUTEX& mutex, bool useMutex) :
      -
      4759  m_pMutex(useMutex ? &mutex : VMA_NULL)
      -
      4760  { if(m_pMutex) { m_pMutex->LockWrite(); } }
      -
      4761  ~VmaMutexLockWrite() { if(m_pMutex) { m_pMutex->UnlockWrite(); } }
      -
      4762 private:
      -
      4763  VMA_RW_MUTEX* m_pMutex;
      -
      4764 };
      -
      4765 
      -
      4766 #if VMA_DEBUG_GLOBAL_MUTEX
      -
      4767  static VMA_MUTEX gDebugGlobalMutex;
      -
      4768  #define VMA_DEBUG_GLOBAL_MUTEX_LOCK VmaMutexLock debugGlobalMutexLock(gDebugGlobalMutex, true);
      -
      4769 #else
      -
      4770  #define VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      4771 #endif
      -
      4772 
      -
      4773 // Minimum size of a free suballocation to register it in the free suballocation collection.
      -
      4774 static const VkDeviceSize VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER = 16;
      -
      4775 
      -
      4776 /*
      -
      4777 Performs binary search and returns iterator to first element that is greater or
      -
      4778 equal to (key), according to comparison (cmp).
      -
      4779 
      -
      4780 Cmp should return true if first argument is less than second argument.
      -
      4781 
      -
      4782 Returned value is the found element, if present in the collection or place where
      -
      4783 new element with value (key) should be inserted.
      -
      4784 */
      -
      4785 template <typename CmpLess, typename IterT, typename KeyT>
      -
      4786 static IterT VmaBinaryFindFirstNotLess(IterT beg, IterT end, const KeyT &key, const CmpLess& cmp)
      -
      4787 {
      -
      4788  size_t down = 0, up = (end - beg);
      -
      4789  while(down < up)
      -
      4790  {
      -
      4791  const size_t mid = down + (up - down) / 2; // Overflow-safe midpoint calculation
      -
      4792  if(cmp(*(beg+mid), key))
      +
      4667  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR ||
      +
      4668  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
      +
      4669  case VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR:
      +
      4670  return
      +
      4671  suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
      +
      4672  case VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL:
      +
      4673  return false;
      +
      4674  default:
      +
      4675  VMA_ASSERT(0);
      +
      4676  return true;
      +
      4677  }
      +
      4678 }
      +
      4679 
      +
      4680 static void VmaWriteMagicValue(void* pData, VkDeviceSize offset)
      +
      4681 {
      +
      4682 #if VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_DETECT_CORRUPTION
      +
      4683  uint32_t* pDst = (uint32_t*)((char*)pData + offset);
      +
      4684  const size_t numberCount = VMA_DEBUG_MARGIN / sizeof(uint32_t);
      +
      4685  for(size_t i = 0; i < numberCount; ++i, ++pDst)
      +
      4686  {
      +
      4687  *pDst = VMA_CORRUPTION_DETECTION_MAGIC_VALUE;
      +
      4688  }
      +
      4689 #else
      +
      4690  // no-op
      +
      4691 #endif
      +
      4692 }
      +
      4693 
      +
      4694 static bool VmaValidateMagicValue(const void* pData, VkDeviceSize offset)
      +
      4695 {
      +
      4696 #if VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_DETECT_CORRUPTION
      +
      4697  const uint32_t* pSrc = (const uint32_t*)((const char*)pData + offset);
      +
      4698  const size_t numberCount = VMA_DEBUG_MARGIN / sizeof(uint32_t);
      +
      4699  for(size_t i = 0; i < numberCount; ++i, ++pSrc)
      +
      4700  {
      +
      4701  if(*pSrc != VMA_CORRUPTION_DETECTION_MAGIC_VALUE)
      +
      4702  {
      +
      4703  return false;
      +
      4704  }
      +
      4705  }
      +
      4706 #endif
      +
      4707  return true;
      +
      4708 }
      +
      4709 
      +
      4710 /*
      +
      4711 Fills structure with parameters of an example buffer to be used for transfers
      +
      4712 during GPU memory defragmentation.
      +
      4713 */
      +
      4714 static void VmaFillGpuDefragmentationBufferCreateInfo(VkBufferCreateInfo& outBufCreateInfo)
      +
      4715 {
      +
      4716  memset(&outBufCreateInfo, 0, sizeof(outBufCreateInfo));
      +
      4717  outBufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
      +
      4718  outBufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
      +
      4719  outBufCreateInfo.size = (VkDeviceSize)VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE; // Example size.
      +
      4720 }
      +
      4721 
      +
      4722 // Helper RAII class to lock a mutex in constructor and unlock it in destructor (at the end of scope).
      +
      4723 struct VmaMutexLock
      +
      4724 {
      +
      4725  VMA_CLASS_NO_COPY(VmaMutexLock)
      +
      4726 public:
      +
      4727  VmaMutexLock(VMA_MUTEX& mutex, bool useMutex = true) :
      +
      4728  m_pMutex(useMutex ? &mutex : VMA_NULL)
      +
      4729  { if(m_pMutex) { m_pMutex->Lock(); } }
      +
      4730  ~VmaMutexLock()
      +
      4731  { if(m_pMutex) { m_pMutex->Unlock(); } }
      +
      4732 private:
      +
      4733  VMA_MUTEX* m_pMutex;
      +
      4734 };
      +
      4735 
      +
      4736 // Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for reading.
      +
      4737 struct VmaMutexLockRead
      +
      4738 {
      +
      4739  VMA_CLASS_NO_COPY(VmaMutexLockRead)
      +
      4740 public:
      +
      4741  VmaMutexLockRead(VMA_RW_MUTEX& mutex, bool useMutex) :
      +
      4742  m_pMutex(useMutex ? &mutex : VMA_NULL)
      +
      4743  { if(m_pMutex) { m_pMutex->LockRead(); } }
      +
      4744  ~VmaMutexLockRead() { if(m_pMutex) { m_pMutex->UnlockRead(); } }
      +
      4745 private:
      +
      4746  VMA_RW_MUTEX* m_pMutex;
      +
      4747 };
      +
      4748 
      +
      4749 // Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for writing.
      +
      4750 struct VmaMutexLockWrite
      +
      4751 {
      +
      4752  VMA_CLASS_NO_COPY(VmaMutexLockWrite)
      +
      4753 public:
      +
      4754  VmaMutexLockWrite(VMA_RW_MUTEX& mutex, bool useMutex) :
      +
      4755  m_pMutex(useMutex ? &mutex : VMA_NULL)
      +
      4756  { if(m_pMutex) { m_pMutex->LockWrite(); } }
      +
      4757  ~VmaMutexLockWrite() { if(m_pMutex) { m_pMutex->UnlockWrite(); } }
      +
      4758 private:
      +
      4759  VMA_RW_MUTEX* m_pMutex;
      +
      4760 };
      +
      4761 
      +
      4762 #if VMA_DEBUG_GLOBAL_MUTEX
      +
      4763  static VMA_MUTEX gDebugGlobalMutex;
      +
      4764  #define VMA_DEBUG_GLOBAL_MUTEX_LOCK VmaMutexLock debugGlobalMutexLock(gDebugGlobalMutex, true);
      +
      4765 #else
      +
      4766  #define VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      4767 #endif
      +
      4768 
      +
      4769 // Minimum size of a free suballocation to register it in the free suballocation collection.
      +
      4770 static const VkDeviceSize VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER = 16;
      +
      4771 
      +
      4772 /*
      +
      4773 Performs binary search and returns iterator to first element that is greater or
      +
      4774 equal to (key), according to comparison (cmp).
      +
      4775 
      +
      4776 Cmp should return true if first argument is less than second argument.
      +
      4777 
      +
      4778 Returned value is the found element, if present in the collection or place where
      +
      4779 new element with value (key) should be inserted.
      +
      4780 */
      +
      4781 template <typename CmpLess, typename IterT, typename KeyT>
      +
      4782 static IterT VmaBinaryFindFirstNotLess(IterT beg, IterT end, const KeyT &key, const CmpLess& cmp)
      +
      4783 {
      +
      4784  size_t down = 0, up = (end - beg);
      +
      4785  while(down < up)
      +
      4786  {
      +
      4787  const size_t mid = down + (up - down) / 2; // Overflow-safe midpoint calculation
      +
      4788  if(cmp(*(beg+mid), key))
      +
      4789  {
      +
      4790  down = mid + 1;
      +
      4791  }
      +
      4792  else
      4793  {
      -
      4794  down = mid + 1;
      +
      4794  up = mid;
      4795  }
      -
      4796  else
      -
      4797  {
      -
      4798  up = mid;
      -
      4799  }
      -
      4800  }
      -
      4801  return beg + down;
      -
      4802 }
      -
      4803 
      -
      4804 template<typename CmpLess, typename IterT, typename KeyT>
      -
      4805 IterT VmaBinaryFindSorted(const IterT& beg, const IterT& end, const KeyT& value, const CmpLess& cmp)
      -
      4806 {
      -
      4807  IterT it = VmaBinaryFindFirstNotLess<CmpLess, IterT, KeyT>(
      -
      4808  beg, end, value, cmp);
      -
      4809  if(it == end ||
      -
      4810  (!cmp(*it, value) && !cmp(value, *it)))
      -
      4811  {
      -
      4812  return it;
      -
      4813  }
      -
      4814  return end;
      -
      4815 }
      -
      4816 
      -
      4817 /*
      -
      4818 Returns true if all pointers in the array are not-null and unique.
      -
      4819 Warning! O(n^2) complexity. Use only inside VMA_HEAVY_ASSERT.
      -
      4820 T must be pointer type, e.g. VmaAllocation, VmaPool.
      -
      4821 */
      -
      4822 template<typename T>
      -
      4823 static bool VmaValidatePointerArray(uint32_t count, const T* arr)
      -
      4824 {
      -
      4825  for(uint32_t i = 0; i < count; ++i)
      -
      4826  {
      -
      4827  const T iPtr = arr[i];
      -
      4828  if(iPtr == VMA_NULL)
      +
      4796  }
      +
      4797  return beg + down;
      +
      4798 }
      +
      4799 
      +
      4800 template<typename CmpLess, typename IterT, typename KeyT>
      +
      4801 IterT VmaBinaryFindSorted(const IterT& beg, const IterT& end, const KeyT& value, const CmpLess& cmp)
      +
      4802 {
      +
      4803  IterT it = VmaBinaryFindFirstNotLess<CmpLess, IterT, KeyT>(
      +
      4804  beg, end, value, cmp);
      +
      4805  if(it == end ||
      +
      4806  (!cmp(*it, value) && !cmp(value, *it)))
      +
      4807  {
      +
      4808  return it;
      +
      4809  }
      +
      4810  return end;
      +
      4811 }
      +
      4812 
      +
      4813 /*
      +
      4814 Returns true if all pointers in the array are not-null and unique.
      +
      4815 Warning! O(n^2) complexity. Use only inside VMA_HEAVY_ASSERT.
      +
      4816 T must be pointer type, e.g. VmaAllocation, VmaPool.
      +
      4817 */
      +
      4818 template<typename T>
      +
      4819 static bool VmaValidatePointerArray(uint32_t count, const T* arr)
      +
      4820 {
      +
      4821  for(uint32_t i = 0; i < count; ++i)
      +
      4822  {
      +
      4823  const T iPtr = arr[i];
      +
      4824  if(iPtr == VMA_NULL)
      +
      4825  {
      +
      4826  return false;
      +
      4827  }
      +
      4828  for(uint32_t j = i + 1; j < count; ++j)
      4829  {
      -
      4830  return false;
      -
      4831  }
      -
      4832  for(uint32_t j = i + 1; j < count; ++j)
      -
      4833  {
      -
      4834  if(iPtr == arr[j])
      -
      4835  {
      -
      4836  return false;
      -
      4837  }
      -
      4838  }
      -
      4839  }
      -
      4840  return true;
      -
      4841 }
      -
      4842 
      -
      4843 template<typename MainT, typename NewT>
      -
      4844 static inline void VmaPnextChainPushFront(MainT* mainStruct, NewT* newStruct)
      -
      4845 {
      -
      4846  newStruct->pNext = mainStruct->pNext;
      -
      4847  mainStruct->pNext = newStruct;
      -
      4848 }
      -
      4849 
      -
      4851 // Memory allocation
      -
      4852 
      -
      4853 static void* VmaMalloc(const VkAllocationCallbacks* pAllocationCallbacks, size_t size, size_t alignment)
      -
      4854 {
      -
      4855  void* result = VMA_NULL;
      -
      4856  if((pAllocationCallbacks != VMA_NULL) &&
      -
      4857  (pAllocationCallbacks->pfnAllocation != VMA_NULL))
      -
      4858  {
      -
      4859  result = (*pAllocationCallbacks->pfnAllocation)(
      -
      4860  pAllocationCallbacks->pUserData,
      -
      4861  size,
      -
      4862  alignment,
      -
      4863  VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
      +
      4830  if(iPtr == arr[j])
      +
      4831  {
      +
      4832  return false;
      +
      4833  }
      +
      4834  }
      +
      4835  }
      +
      4836  return true;
      +
      4837 }
      +
      4838 
      +
      4839 template<typename MainT, typename NewT>
      +
      4840 static inline void VmaPnextChainPushFront(MainT* mainStruct, NewT* newStruct)
      +
      4841 {
      +
      4842  newStruct->pNext = mainStruct->pNext;
      +
      4843  mainStruct->pNext = newStruct;
      +
      4844 }
      +
      4845 
      +
      4847 // Memory allocation
      +
      4848 
      +
      4849 static void* VmaMalloc(const VkAllocationCallbacks* pAllocationCallbacks, size_t size, size_t alignment)
      +
      4850 {
      +
      4851  void* result = VMA_NULL;
      +
      4852  if((pAllocationCallbacks != VMA_NULL) &&
      +
      4853  (pAllocationCallbacks->pfnAllocation != VMA_NULL))
      +
      4854  {
      +
      4855  result = (*pAllocationCallbacks->pfnAllocation)(
      +
      4856  pAllocationCallbacks->pUserData,
      +
      4857  size,
      +
      4858  alignment,
      +
      4859  VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
      +
      4860  }
      +
      4861  else
      +
      4862  {
      +
      4863  result = VMA_SYSTEM_ALIGNED_MALLOC(size, alignment);
      4864  }
      -
      4865  else
      -
      4866  {
      -
      4867  result = VMA_SYSTEM_ALIGNED_MALLOC(size, alignment);
      -
      4868  }
      -
      4869  VMA_ASSERT(result != VMA_NULL && "CPU memory allocation failed.");
      -
      4870  return result;
      -
      4871 }
      -
      4872 
      -
      4873 static void VmaFree(const VkAllocationCallbacks* pAllocationCallbacks, void* ptr)
      -
      4874 {
      -
      4875  if((pAllocationCallbacks != VMA_NULL) &&
      -
      4876  (pAllocationCallbacks->pfnFree != VMA_NULL))
      +
      4865  VMA_ASSERT(result != VMA_NULL && "CPU memory allocation failed.");
      +
      4866  return result;
      +
      4867 }
      +
      4868 
      +
      4869 static void VmaFree(const VkAllocationCallbacks* pAllocationCallbacks, void* ptr)
      +
      4870 {
      +
      4871  if((pAllocationCallbacks != VMA_NULL) &&
      +
      4872  (pAllocationCallbacks->pfnFree != VMA_NULL))
      +
      4873  {
      +
      4874  (*pAllocationCallbacks->pfnFree)(pAllocationCallbacks->pUserData, ptr);
      +
      4875  }
      +
      4876  else
      4877  {
      -
      4878  (*pAllocationCallbacks->pfnFree)(pAllocationCallbacks->pUserData, ptr);
      +
      4878  VMA_SYSTEM_ALIGNED_FREE(ptr);
      4879  }
      -
      4880  else
      -
      4881  {
      -
      4882  VMA_SYSTEM_ALIGNED_FREE(ptr);
      -
      4883  }
      -
      4884 }
      -
      4885 
      -
      4886 template<typename T>
      -
      4887 static T* VmaAllocate(const VkAllocationCallbacks* pAllocationCallbacks)
      -
      4888 {
      -
      4889  return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T), VMA_ALIGN_OF(T));
      -
      4890 }
      -
      4891 
      -
      4892 template<typename T>
      -
      4893 static T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, size_t count)
      -
      4894 {
      -
      4895  return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T) * count, VMA_ALIGN_OF(T));
      -
      4896 }
      +
      4880 }
      +
      4881 
      +
      4882 template<typename T>
      +
      4883 static T* VmaAllocate(const VkAllocationCallbacks* pAllocationCallbacks)
      +
      4884 {
      +
      4885  return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T), VMA_ALIGN_OF(T));
      +
      4886 }
      +
      4887 
      +
      4888 template<typename T>
      +
      4889 static T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, size_t count)
      +
      4890 {
      +
      4891  return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T) * count, VMA_ALIGN_OF(T));
      +
      4892 }
      +
      4893 
      +
      4894 #define vma_new(allocator, type) new(VmaAllocate<type>(allocator))(type)
      +
      4895 
      +
      4896 #define vma_new_array(allocator, type, count) new(VmaAllocateArray<type>((allocator), (count)))(type)
      4897 
      -
      4898 #define vma_new(allocator, type) new(VmaAllocate<type>(allocator))(type)
      -
      4899 
      -
      4900 #define vma_new_array(allocator, type, count) new(VmaAllocateArray<type>((allocator), (count)))(type)
      -
      4901 
      -
      4902 template<typename T>
      -
      4903 static void vma_delete(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr)
      -
      4904 {
      -
      4905  ptr->~T();
      -
      4906  VmaFree(pAllocationCallbacks, ptr);
      -
      4907 }
      -
      4908 
      -
      4909 template<typename T>
      -
      4910 static void vma_delete_array(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr, size_t count)
      -
      4911 {
      -
      4912  if(ptr != VMA_NULL)
      -
      4913  {
      -
      4914  for(size_t i = count; i--; )
      -
      4915  {
      -
      4916  ptr[i].~T();
      -
      4917  }
      -
      4918  VmaFree(pAllocationCallbacks, ptr);
      -
      4919  }
      -
      4920 }
      -
      4921 
      -
      4922 static char* VmaCreateStringCopy(const VkAllocationCallbacks* allocs, const char* srcStr)
      -
      4923 {
      -
      4924  if(srcStr != VMA_NULL)
      -
      4925  {
      -
      4926  const size_t len = strlen(srcStr);
      -
      4927  char* const result = vma_new_array(allocs, char, len + 1);
      -
      4928  memcpy(result, srcStr, len + 1);
      -
      4929  return result;
      +
      4898 template<typename T>
      +
      4899 static void vma_delete(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr)
      +
      4900 {
      +
      4901  ptr->~T();
      +
      4902  VmaFree(pAllocationCallbacks, ptr);
      +
      4903 }
      +
      4904 
      +
      4905 template<typename T>
      +
      4906 static void vma_delete_array(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr, size_t count)
      +
      4907 {
      +
      4908  if(ptr != VMA_NULL)
      +
      4909  {
      +
      4910  for(size_t i = count; i--; )
      +
      4911  {
      +
      4912  ptr[i].~T();
      +
      4913  }
      +
      4914  VmaFree(pAllocationCallbacks, ptr);
      +
      4915  }
      +
      4916 }
      +
      4917 
      +
      4918 static char* VmaCreateStringCopy(const VkAllocationCallbacks* allocs, const char* srcStr)
      +
      4919 {
      +
      4920  if(srcStr != VMA_NULL)
      +
      4921  {
      +
      4922  const size_t len = strlen(srcStr);
      +
      4923  char* const result = vma_new_array(allocs, char, len + 1);
      +
      4924  memcpy(result, srcStr, len + 1);
      +
      4925  return result;
      +
      4926  }
      +
      4927  else
      +
      4928  {
      +
      4929  return VMA_NULL;
      4930  }
      -
      4931  else
      -
      4932  {
      -
      4933  return VMA_NULL;
      -
      4934  }
      -
      4935 }
      -
      4936 
      -
      4937 static void VmaFreeString(const VkAllocationCallbacks* allocs, char* str)
      -
      4938 {
      -
      4939  if(str != VMA_NULL)
      -
      4940  {
      -
      4941  const size_t len = strlen(str);
      -
      4942  vma_delete_array(allocs, str, len + 1);
      -
      4943  }
      -
      4944 }
      -
      4945 
      -
      4946 // STL-compatible allocator.
      -
      4947 template<typename T>
      -
      4948 class VmaStlAllocator
      -
      4949 {
      -
      4950 public:
      -
      4951  const VkAllocationCallbacks* const m_pCallbacks;
      -
      4952  typedef T value_type;
      -
      4953 
      -
      4954  VmaStlAllocator(const VkAllocationCallbacks* pCallbacks) : m_pCallbacks(pCallbacks) { }
      -
      4955  template<typename U> VmaStlAllocator(const VmaStlAllocator<U>& src) : m_pCallbacks(src.m_pCallbacks) { }
      -
      4956 
      -
      4957  T* allocate(size_t n) { return VmaAllocateArray<T>(m_pCallbacks, n); }
      -
      4958  void deallocate(T* p, size_t n) { VmaFree(m_pCallbacks, p); }
      -
      4959 
      -
      4960  template<typename U>
      -
      4961  bool operator==(const VmaStlAllocator<U>& rhs) const
      -
      4962  {
      -
      4963  return m_pCallbacks == rhs.m_pCallbacks;
      -
      4964  }
      -
      4965  template<typename U>
      -
      4966  bool operator!=(const VmaStlAllocator<U>& rhs) const
      -
      4967  {
      -
      4968  return m_pCallbacks != rhs.m_pCallbacks;
      -
      4969  }
      -
      4970 
      -
      4971  VmaStlAllocator& operator=(const VmaStlAllocator& x) = delete;
      -
      4972 };
      +
      4931 }
      +
      4932 
      +
      4933 static void VmaFreeString(const VkAllocationCallbacks* allocs, char* str)
      +
      4934 {
      +
      4935  if(str != VMA_NULL)
      +
      4936  {
      +
      4937  const size_t len = strlen(str);
      +
      4938  vma_delete_array(allocs, str, len + 1);
      +
      4939  }
      +
      4940 }
      +
      4941 
      +
      4942 // STL-compatible allocator.
      +
      4943 template<typename T>
      +
      4944 class VmaStlAllocator
      +
      4945 {
      +
      4946 public:
      +
      4947  const VkAllocationCallbacks* const m_pCallbacks;
      +
      4948  typedef T value_type;
      +
      4949 
      +
      4950  VmaStlAllocator(const VkAllocationCallbacks* pCallbacks) : m_pCallbacks(pCallbacks) { }
      +
      4951  template<typename U> VmaStlAllocator(const VmaStlAllocator<U>& src) : m_pCallbacks(src.m_pCallbacks) { }
      +
      4952 
      +
      4953  T* allocate(size_t n) { return VmaAllocateArray<T>(m_pCallbacks, n); }
      +
      4954  void deallocate(T* p, size_t n) { VmaFree(m_pCallbacks, p); }
      +
      4955 
      +
      4956  template<typename U>
      +
      4957  bool operator==(const VmaStlAllocator<U>& rhs) const
      +
      4958  {
      +
      4959  return m_pCallbacks == rhs.m_pCallbacks;
      +
      4960  }
      +
      4961  template<typename U>
      +
      4962  bool operator!=(const VmaStlAllocator<U>& rhs) const
      +
      4963  {
      +
      4964  return m_pCallbacks != rhs.m_pCallbacks;
      +
      4965  }
      +
      4966 
      +
      4967  VmaStlAllocator& operator=(const VmaStlAllocator& x) = delete;
      +
      4968 };
      +
      4969 
      +
      4970 #if VMA_USE_STL_VECTOR
      +
      4971 
      +
      4972 #define VmaVector std::vector
      4973 
      -
      4974 #if VMA_USE_STL_VECTOR
      -
      4975 
      -
      4976 #define VmaVector std::vector
      -
      4977 
      -
      4978 template<typename T, typename allocatorT>
      -
      4979 static void VmaVectorInsert(std::vector<T, allocatorT>& vec, size_t index, const T& item)
      -
      4980 {
      -
      4981  vec.insert(vec.begin() + index, item);
      -
      4982 }
      -
      4983 
      -
      4984 template<typename T, typename allocatorT>
      -
      4985 static void VmaVectorRemove(std::vector<T, allocatorT>& vec, size_t index)
      -
      4986 {
      -
      4987  vec.erase(vec.begin() + index);
      -
      4988 }
      -
      4989 
      -
      4990 #else // #if VMA_USE_STL_VECTOR
      -
      4991 
      -
      4992 /* Class with interface compatible with subset of std::vector.
      -
      4993 T must be POD because constructors and destructors are not called and memcpy is
      -
      4994 used for these objects. */
      -
      4995 template<typename T, typename AllocatorT>
      -
      4996 class VmaVector
      -
      4997 {
      -
      4998 public:
      -
      4999  typedef T value_type;
      -
      5000 
      -
      5001  VmaVector(const AllocatorT& allocator) :
      -
      5002  m_Allocator(allocator),
      -
      5003  m_pArray(VMA_NULL),
      -
      5004  m_Count(0),
      -
      5005  m_Capacity(0)
      -
      5006  {
      -
      5007  }
      -
      5008 
      -
      5009  VmaVector(size_t count, const AllocatorT& allocator) :
      -
      5010  m_Allocator(allocator),
      -
      5011  m_pArray(count ? (T*)VmaAllocateArray<T>(allocator.m_pCallbacks, count) : VMA_NULL),
      -
      5012  m_Count(count),
      -
      5013  m_Capacity(count)
      -
      5014  {
      -
      5015  }
      -
      5016 
      -
      5017  // This version of the constructor is here for compatibility with pre-C++14 std::vector.
      -
      5018  // value is unused.
      -
      5019  VmaVector(size_t count, const T& value, const AllocatorT& allocator)
      -
      5020  : VmaVector(count, allocator) {}
      -
      5021 
      -
      5022  VmaVector(const VmaVector<T, AllocatorT>& src) :
      -
      5023  m_Allocator(src.m_Allocator),
      -
      5024  m_pArray(src.m_Count ? (T*)VmaAllocateArray<T>(src.m_Allocator.m_pCallbacks, src.m_Count) : VMA_NULL),
      -
      5025  m_Count(src.m_Count),
      -
      5026  m_Capacity(src.m_Count)
      -
      5027  {
      -
      5028  if(m_Count != 0)
      -
      5029  {
      -
      5030  memcpy(m_pArray, src.m_pArray, m_Count * sizeof(T));
      -
      5031  }
      -
      5032  }
      -
      5033 
      -
      5034  ~VmaVector()
      -
      5035  {
      -
      5036  VmaFree(m_Allocator.m_pCallbacks, m_pArray);
      -
      5037  }
      -
      5038 
      -
      5039  VmaVector& operator=(const VmaVector<T, AllocatorT>& rhs)
      -
      5040  {
      -
      5041  if(&rhs != this)
      -
      5042  {
      -
      5043  resize(rhs.m_Count);
      -
      5044  if(m_Count != 0)
      -
      5045  {
      -
      5046  memcpy(m_pArray, rhs.m_pArray, m_Count * sizeof(T));
      -
      5047  }
      -
      5048  }
      -
      5049  return *this;
      -
      5050  }
      -
      5051 
      -
      5052  bool empty() const { return m_Count == 0; }
      -
      5053  size_t size() const { return m_Count; }
      -
      5054  T* data() { return m_pArray; }
      -
      5055  const T* data() const { return m_pArray; }
      -
      5056 
      -
      5057  T& operator[](size_t index)
      -
      5058  {
      -
      5059  VMA_HEAVY_ASSERT(index < m_Count);
      -
      5060  return m_pArray[index];
      -
      5061  }
      -
      5062  const T& operator[](size_t index) const
      -
      5063  {
      -
      5064  VMA_HEAVY_ASSERT(index < m_Count);
      -
      5065  return m_pArray[index];
      -
      5066  }
      -
      5067 
      -
      5068  T& front()
      -
      5069  {
      -
      5070  VMA_HEAVY_ASSERT(m_Count > 0);
      -
      5071  return m_pArray[0];
      -
      5072  }
      -
      5073  const T& front() const
      -
      5074  {
      -
      5075  VMA_HEAVY_ASSERT(m_Count > 0);
      -
      5076  return m_pArray[0];
      -
      5077  }
      -
      5078  T& back()
      -
      5079  {
      -
      5080  VMA_HEAVY_ASSERT(m_Count > 0);
      -
      5081  return m_pArray[m_Count - 1];
      -
      5082  }
      -
      5083  const T& back() const
      -
      5084  {
      -
      5085  VMA_HEAVY_ASSERT(m_Count > 0);
      -
      5086  return m_pArray[m_Count - 1];
      -
      5087  }
      +
      4974 template<typename T, typename allocatorT>
      +
      4975 static void VmaVectorInsert(std::vector<T, allocatorT>& vec, size_t index, const T& item)
      +
      4976 {
      +
      4977  vec.insert(vec.begin() + index, item);
      +
      4978 }
      +
      4979 
      +
      4980 template<typename T, typename allocatorT>
      +
      4981 static void VmaVectorRemove(std::vector<T, allocatorT>& vec, size_t index)
      +
      4982 {
      +
      4983  vec.erase(vec.begin() + index);
      +
      4984 }
      +
      4985 
      +
      4986 #else // #if VMA_USE_STL_VECTOR
      +
      4987 
      +
      4988 /* Class with interface compatible with subset of std::vector.
      +
      4989 T must be POD because constructors and destructors are not called and memcpy is
      +
      4990 used for these objects. */
      +
      4991 template<typename T, typename AllocatorT>
      +
      4992 class VmaVector
      +
      4993 {
      +
      4994 public:
      +
      4995  typedef T value_type;
      +
      4996 
      +
      4997  VmaVector(const AllocatorT& allocator) :
      +
      4998  m_Allocator(allocator),
      +
      4999  m_pArray(VMA_NULL),
      +
      5000  m_Count(0),
      +
      5001  m_Capacity(0)
      +
      5002  {
      +
      5003  }
      +
      5004 
      +
      5005  VmaVector(size_t count, const AllocatorT& allocator) :
      +
      5006  m_Allocator(allocator),
      +
      5007  m_pArray(count ? (T*)VmaAllocateArray<T>(allocator.m_pCallbacks, count) : VMA_NULL),
      +
      5008  m_Count(count),
      +
      5009  m_Capacity(count)
      +
      5010  {
      +
      5011  }
      +
      5012 
      +
      5013  // This version of the constructor is here for compatibility with pre-C++14 std::vector.
      +
      5014  // value is unused.
      +
      5015  VmaVector(size_t count, const T& value, const AllocatorT& allocator)
      +
      5016  : VmaVector(count, allocator) {}
      +
      5017 
      +
      5018  VmaVector(const VmaVector<T, AllocatorT>& src) :
      +
      5019  m_Allocator(src.m_Allocator),
      +
      5020  m_pArray(src.m_Count ? (T*)VmaAllocateArray<T>(src.m_Allocator.m_pCallbacks, src.m_Count) : VMA_NULL),
      +
      5021  m_Count(src.m_Count),
      +
      5022  m_Capacity(src.m_Count)
      +
      5023  {
      +
      5024  if(m_Count != 0)
      +
      5025  {
      +
      5026  memcpy(m_pArray, src.m_pArray, m_Count * sizeof(T));
      +
      5027  }
      +
      5028  }
      +
      5029 
      +
      5030  ~VmaVector()
      +
      5031  {
      +
      5032  VmaFree(m_Allocator.m_pCallbacks, m_pArray);
      +
      5033  }
      +
      5034 
      +
      5035  VmaVector& operator=(const VmaVector<T, AllocatorT>& rhs)
      +
      5036  {
      +
      5037  if(&rhs != this)
      +
      5038  {
      +
      5039  resize(rhs.m_Count);
      +
      5040  if(m_Count != 0)
      +
      5041  {
      +
      5042  memcpy(m_pArray, rhs.m_pArray, m_Count * sizeof(T));
      +
      5043  }
      +
      5044  }
      +
      5045  return *this;
      +
      5046  }
      +
      5047 
      +
      5048  bool empty() const { return m_Count == 0; }
      +
      5049  size_t size() const { return m_Count; }
      +
      5050  T* data() { return m_pArray; }
      +
      5051  const T* data() const { return m_pArray; }
      +
      5052 
      +
      5053  T& operator[](size_t index)
      +
      5054  {
      +
      5055  VMA_HEAVY_ASSERT(index < m_Count);
      +
      5056  return m_pArray[index];
      +
      5057  }
      +
      5058  const T& operator[](size_t index) const
      +
      5059  {
      +
      5060  VMA_HEAVY_ASSERT(index < m_Count);
      +
      5061  return m_pArray[index];
      +
      5062  }
      +
      5063 
      +
      5064  T& front()
      +
      5065  {
      +
      5066  VMA_HEAVY_ASSERT(m_Count > 0);
      +
      5067  return m_pArray[0];
      +
      5068  }
      +
      5069  const T& front() const
      +
      5070  {
      +
      5071  VMA_HEAVY_ASSERT(m_Count > 0);
      +
      5072  return m_pArray[0];
      +
      5073  }
      +
      5074  T& back()
      +
      5075  {
      +
      5076  VMA_HEAVY_ASSERT(m_Count > 0);
      +
      5077  return m_pArray[m_Count - 1];
      +
      5078  }
      +
      5079  const T& back() const
      +
      5080  {
      +
      5081  VMA_HEAVY_ASSERT(m_Count > 0);
      +
      5082  return m_pArray[m_Count - 1];
      +
      5083  }
      +
      5084 
      +
      5085  void reserve(size_t newCapacity, bool freeMemory = false)
      +
      5086  {
      +
      5087  newCapacity = VMA_MAX(newCapacity, m_Count);
      5088 
      -
      5089  void reserve(size_t newCapacity, bool freeMemory = false)
      -
      5090  {
      -
      5091  newCapacity = VMA_MAX(newCapacity, m_Count);
      -
      5092 
      -
      5093  if((newCapacity < m_Capacity) && !freeMemory)
      -
      5094  {
      -
      5095  newCapacity = m_Capacity;
      -
      5096  }
      -
      5097 
      -
      5098  if(newCapacity != m_Capacity)
      -
      5099  {
      -
      5100  T* const newArray = newCapacity ? VmaAllocateArray<T>(m_Allocator, newCapacity) : VMA_NULL;
      -
      5101  if(m_Count != 0)
      -
      5102  {
      -
      5103  memcpy(newArray, m_pArray, m_Count * sizeof(T));
      -
      5104  }
      -
      5105  VmaFree(m_Allocator.m_pCallbacks, m_pArray);
      -
      5106  m_Capacity = newCapacity;
      -
      5107  m_pArray = newArray;
      -
      5108  }
      -
      5109  }
      -
      5110 
      -
      5111  void resize(size_t newCount, bool freeMemory = false)
      -
      5112  {
      -
      5113  size_t newCapacity = m_Capacity;
      -
      5114  if(newCount > m_Capacity)
      +
      5089  if((newCapacity < m_Capacity) && !freeMemory)
      +
      5090  {
      +
      5091  newCapacity = m_Capacity;
      +
      5092  }
      +
      5093 
      +
      5094  if(newCapacity != m_Capacity)
      +
      5095  {
      +
      5096  T* const newArray = newCapacity ? VmaAllocateArray<T>(m_Allocator, newCapacity) : VMA_NULL;
      +
      5097  if(m_Count != 0)
      +
      5098  {
      +
      5099  memcpy(newArray, m_pArray, m_Count * sizeof(T));
      +
      5100  }
      +
      5101  VmaFree(m_Allocator.m_pCallbacks, m_pArray);
      +
      5102  m_Capacity = newCapacity;
      +
      5103  m_pArray = newArray;
      +
      5104  }
      +
      5105  }
      +
      5106 
      +
      5107  void resize(size_t newCount, bool freeMemory = false)
      +
      5108  {
      +
      5109  size_t newCapacity = m_Capacity;
      +
      5110  if(newCount > m_Capacity)
      +
      5111  {
      +
      5112  newCapacity = VMA_MAX(newCount, VMA_MAX(m_Capacity * 3 / 2, (size_t)8));
      +
      5113  }
      +
      5114  else if(freeMemory)
      5115  {
      -
      5116  newCapacity = VMA_MAX(newCount, VMA_MAX(m_Capacity * 3 / 2, (size_t)8));
      +
      5116  newCapacity = newCount;
      5117  }
      -
      5118  else if(freeMemory)
      -
      5119  {
      -
      5120  newCapacity = newCount;
      -
      5121  }
      -
      5122 
      -
      5123  if(newCapacity != m_Capacity)
      -
      5124  {
      -
      5125  T* const newArray = newCapacity ? VmaAllocateArray<T>(m_Allocator.m_pCallbacks, newCapacity) : VMA_NULL;
      -
      5126  const size_t elementsToCopy = VMA_MIN(m_Count, newCount);
      -
      5127  if(elementsToCopy != 0)
      -
      5128  {
      -
      5129  memcpy(newArray, m_pArray, elementsToCopy * sizeof(T));
      -
      5130  }
      -
      5131  VmaFree(m_Allocator.m_pCallbacks, m_pArray);
      -
      5132  m_Capacity = newCapacity;
      -
      5133  m_pArray = newArray;
      -
      5134  }
      -
      5135 
      -
      5136  m_Count = newCount;
      -
      5137  }
      -
      5138 
      -
      5139  void clear(bool freeMemory = false)
      -
      5140  {
      -
      5141  resize(0, freeMemory);
      -
      5142  }
      -
      5143 
      -
      5144  void insert(size_t index, const T& src)
      -
      5145  {
      -
      5146  VMA_HEAVY_ASSERT(index <= m_Count);
      -
      5147  const size_t oldCount = size();
      -
      5148  resize(oldCount + 1);
      -
      5149  if(index < oldCount)
      -
      5150  {
      -
      5151  memmove(m_pArray + (index + 1), m_pArray + index, (oldCount - index) * sizeof(T));
      -
      5152  }
      -
      5153  m_pArray[index] = src;
      -
      5154  }
      -
      5155 
      -
      5156  void remove(size_t index)
      -
      5157  {
      -
      5158  VMA_HEAVY_ASSERT(index < m_Count);
      -
      5159  const size_t oldCount = size();
      -
      5160  if(index < oldCount - 1)
      -
      5161  {
      -
      5162  memmove(m_pArray + index, m_pArray + (index + 1), (oldCount - index - 1) * sizeof(T));
      -
      5163  }
      -
      5164  resize(oldCount - 1);
      -
      5165  }
      -
      5166 
      -
      5167  void push_back(const T& src)
      -
      5168  {
      -
      5169  const size_t newIndex = size();
      -
      5170  resize(newIndex + 1);
      -
      5171  m_pArray[newIndex] = src;
      -
      5172  }
      -
      5173 
      -
      5174  void pop_back()
      -
      5175  {
      -
      5176  VMA_HEAVY_ASSERT(m_Count > 0);
      -
      5177  resize(size() - 1);
      -
      5178  }
      -
      5179 
      -
      5180  void push_front(const T& src)
      -
      5181  {
      -
      5182  insert(0, src);
      -
      5183  }
      -
      5184 
      -
      5185  void pop_front()
      -
      5186  {
      -
      5187  VMA_HEAVY_ASSERT(m_Count > 0);
      -
      5188  remove(0);
      -
      5189  }
      -
      5190 
      -
      5191  typedef T* iterator;
      -
      5192 
      -
      5193  iterator begin() { return m_pArray; }
      -
      5194  iterator end() { return m_pArray + m_Count; }
      -
      5195 
      -
      5196 private:
      -
      5197  AllocatorT m_Allocator;
      -
      5198  T* m_pArray;
      -
      5199  size_t m_Count;
      -
      5200  size_t m_Capacity;
      -
      5201 };
      -
      5202 
      -
      5203 template<typename T, typename allocatorT>
      -
      5204 static void VmaVectorInsert(VmaVector<T, allocatorT>& vec, size_t index, const T& item)
      -
      5205 {
      -
      5206  vec.insert(index, item);
      -
      5207 }
      -
      5208 
      -
      5209 template<typename T, typename allocatorT>
      -
      5210 static void VmaVectorRemove(VmaVector<T, allocatorT>& vec, size_t index)
      -
      5211 {
      -
      5212  vec.remove(index);
      -
      5213 }
      -
      5214 
      -
      5215 #endif // #if VMA_USE_STL_VECTOR
      -
      5216 
      -
      5217 template<typename CmpLess, typename VectorT>
      -
      5218 size_t VmaVectorInsertSorted(VectorT& vector, const typename VectorT::value_type& value)
      -
      5219 {
      -
      5220  const size_t indexToInsert = VmaBinaryFindFirstNotLess(
      -
      5221  vector.data(),
      -
      5222  vector.data() + vector.size(),
      -
      5223  value,
      -
      5224  CmpLess()) - vector.data();
      -
      5225  VmaVectorInsert(vector, indexToInsert, value);
      -
      5226  return indexToInsert;
      -
      5227 }
      -
      5228 
      -
      5229 template<typename CmpLess, typename VectorT>
      -
      5230 bool VmaVectorRemoveSorted(VectorT& vector, const typename VectorT::value_type& value)
      -
      5231 {
      -
      5232  CmpLess comparator;
      -
      5233  typename VectorT::iterator it = VmaBinaryFindFirstNotLess(
      -
      5234  vector.begin(),
      -
      5235  vector.end(),
      -
      5236  value,
      -
      5237  comparator);
      -
      5238  if((it != vector.end()) && !comparator(*it, value) && !comparator(value, *it))
      -
      5239  {
      -
      5240  size_t indexToRemove = it - vector.begin();
      -
      5241  VmaVectorRemove(vector, indexToRemove);
      -
      5242  return true;
      -
      5243  }
      -
      5244  return false;
      -
      5245 }
      -
      5246 
      -
      5248 // class VmaSmallVector
      -
      5249 
      -
      5250 /*
      -
      5251 This is a vector (a variable-sized array), optimized for the case when the array is small.
      -
      5252 
      -
      5253 It contains some number of elements in-place, which allows it to avoid heap allocation
      -
      5254 when the actual number of elements is below that threshold. This allows normal "small"
      -
      5255 cases to be fast without losing generality for large inputs.
      -
      5256 */
      -
      5257 
      -
      5258 template<typename T, typename AllocatorT, size_t N>
      -
      5259 class VmaSmallVector
      -
      5260 {
      -
      5261 public:
      -
      5262  typedef T value_type;
      -
      5263 
      -
      5264  VmaSmallVector(const AllocatorT& allocator) :
      -
      5265  m_Count(0),
      -
      5266  m_DynamicArray(allocator)
      -
      5267  {
      -
      5268  }
      -
      5269  VmaSmallVector(size_t count, const AllocatorT& allocator) :
      -
      5270  m_Count(count),
      -
      5271  m_DynamicArray(count > N ? count : 0, allocator)
      -
      5272  {
      -
      5273  }
      -
      5274  template<typename SrcT, typename SrcAllocatorT, size_t SrcN>
      -
      5275  VmaSmallVector(const VmaSmallVector<SrcT, SrcAllocatorT, SrcN>& src) = delete;
      -
      5276  template<typename SrcT, typename SrcAllocatorT, size_t SrcN>
      -
      5277  VmaSmallVector<T, AllocatorT, N>& operator=(const VmaSmallVector<SrcT, SrcAllocatorT, SrcN>& rhs) = delete;
      -
      5278 
      -
      5279  bool empty() const { return m_Count == 0; }
      -
      5280  size_t size() const { return m_Count; }
      -
      5281  T* data() { return m_Count > N ? m_DynamicArray.data() : m_StaticArray; }
      -
      5282  const T* data() const { return m_Count > N ? m_DynamicArray.data() : m_StaticArray; }
      -
      5283 
      -
      5284  T& operator[](size_t index)
      -
      5285  {
      -
      5286  VMA_HEAVY_ASSERT(index < m_Count);
      -
      5287  return data()[index];
      -
      5288  }
      -
      5289  const T& operator[](size_t index) const
      -
      5290  {
      -
      5291  VMA_HEAVY_ASSERT(index < m_Count);
      -
      5292  return data()[index];
      -
      5293  }
      -
      5294 
      -
      5295  T& front()
      -
      5296  {
      -
      5297  VMA_HEAVY_ASSERT(m_Count > 0);
      -
      5298  return data()[0];
      -
      5299  }
      -
      5300  const T& front() const
      -
      5301  {
      -
      5302  VMA_HEAVY_ASSERT(m_Count > 0);
      -
      5303  return data()[0];
      -
      5304  }
      -
      5305  T& back()
      -
      5306  {
      -
      5307  VMA_HEAVY_ASSERT(m_Count > 0);
      -
      5308  return data()[m_Count - 1];
      -
      5309  }
      -
      5310  const T& back() const
      -
      5311  {
      -
      5312  VMA_HEAVY_ASSERT(m_Count > 0);
      -
      5313  return data()[m_Count - 1];
      -
      5314  }
      -
      5315 
      -
      5316  void resize(size_t newCount, bool freeMemory = false)
      -
      5317  {
      -
      5318  if(newCount > N && m_Count > N)
      -
      5319  {
      -
      5320  // Any direction, staying in m_DynamicArray
      -
      5321  m_DynamicArray.resize(newCount, freeMemory);
      -
      5322  }
      -
      5323  else if(newCount > N && m_Count <= N)
      -
      5324  {
      -
      5325  // Growing, moving from m_StaticArray to m_DynamicArray
      -
      5326  m_DynamicArray.resize(newCount, freeMemory);
      -
      5327  if(m_Count > 0)
      -
      5328  {
      -
      5329  memcpy(m_DynamicArray.data(), m_StaticArray, m_Count * sizeof(T));
      -
      5330  }
      -
      5331  }
      -
      5332  else if(newCount <= N && m_Count > N)
      -
      5333  {
      -
      5334  // Shrinking, moving from m_DynamicArray to m_StaticArray
      -
      5335  if(newCount > 0)
      -
      5336  {
      -
      5337  memcpy(m_StaticArray, m_DynamicArray.data(), newCount * sizeof(T));
      -
      5338  }
      -
      5339  m_DynamicArray.resize(0, freeMemory);
      +
      5118 
      +
      5119  if(newCapacity != m_Capacity)
      +
      5120  {
      +
      5121  T* const newArray = newCapacity ? VmaAllocateArray<T>(m_Allocator.m_pCallbacks, newCapacity) : VMA_NULL;
      +
      5122  const size_t elementsToCopy = VMA_MIN(m_Count, newCount);
      +
      5123  if(elementsToCopy != 0)
      +
      5124  {
      +
      5125  memcpy(newArray, m_pArray, elementsToCopy * sizeof(T));
      +
      5126  }
      +
      5127  VmaFree(m_Allocator.m_pCallbacks, m_pArray);
      +
      5128  m_Capacity = newCapacity;
      +
      5129  m_pArray = newArray;
      +
      5130  }
      +
      5131 
      +
      5132  m_Count = newCount;
      +
      5133  }
      +
      5134 
      +
      5135  void clear(bool freeMemory = false)
      +
      5136  {
      +
      5137  resize(0, freeMemory);
      +
      5138  }
      +
      5139 
      +
      5140  void insert(size_t index, const T& src)
      +
      5141  {
      +
      5142  VMA_HEAVY_ASSERT(index <= m_Count);
      +
      5143  const size_t oldCount = size();
      +
      5144  resize(oldCount + 1);
      +
      5145  if(index < oldCount)
      +
      5146  {
      +
      5147  memmove(m_pArray + (index + 1), m_pArray + index, (oldCount - index) * sizeof(T));
      +
      5148  }
      +
      5149  m_pArray[index] = src;
      +
      5150  }
      +
      5151 
      +
      5152  void remove(size_t index)
      +
      5153  {
      +
      5154  VMA_HEAVY_ASSERT(index < m_Count);
      +
      5155  const size_t oldCount = size();
      +
      5156  if(index < oldCount - 1)
      +
      5157  {
      +
      5158  memmove(m_pArray + index, m_pArray + (index + 1), (oldCount - index - 1) * sizeof(T));
      +
      5159  }
      +
      5160  resize(oldCount - 1);
      +
      5161  }
      +
      5162 
      +
      5163  void push_back(const T& src)
      +
      5164  {
      +
      5165  const size_t newIndex = size();
      +
      5166  resize(newIndex + 1);
      +
      5167  m_pArray[newIndex] = src;
      +
      5168  }
      +
      5169 
      +
      5170  void pop_back()
      +
      5171  {
      +
      5172  VMA_HEAVY_ASSERT(m_Count > 0);
      +
      5173  resize(size() - 1);
      +
      5174  }
      +
      5175 
      +
      5176  void push_front(const T& src)
      +
      5177  {
      +
      5178  insert(0, src);
      +
      5179  }
      +
      5180 
      +
      5181  void pop_front()
      +
      5182  {
      +
      5183  VMA_HEAVY_ASSERT(m_Count > 0);
      +
      5184  remove(0);
      +
      5185  }
      +
      5186 
      +
      5187  typedef T* iterator;
      +
      5188 
      +
      5189  iterator begin() { return m_pArray; }
      +
      5190  iterator end() { return m_pArray + m_Count; }
      +
      5191 
      +
      5192 private:
      +
      5193  AllocatorT m_Allocator;
      +
      5194  T* m_pArray;
      +
      5195  size_t m_Count;
      +
      5196  size_t m_Capacity;
      +
      5197 };
      +
      5198 
      +
      5199 template<typename T, typename allocatorT>
      +
      5200 static void VmaVectorInsert(VmaVector<T, allocatorT>& vec, size_t index, const T& item)
      +
      5201 {
      +
      5202  vec.insert(index, item);
      +
      5203 }
      +
      5204 
      +
      5205 template<typename T, typename allocatorT>
      +
      5206 static void VmaVectorRemove(VmaVector<T, allocatorT>& vec, size_t index)
      +
      5207 {
      +
      5208  vec.remove(index);
      +
      5209 }
      +
      5210 
      +
      5211 #endif // #if VMA_USE_STL_VECTOR
      +
      5212 
      +
      5213 template<typename CmpLess, typename VectorT>
      +
      5214 size_t VmaVectorInsertSorted(VectorT& vector, const typename VectorT::value_type& value)
      +
      5215 {
      +
      5216  const size_t indexToInsert = VmaBinaryFindFirstNotLess(
      +
      5217  vector.data(),
      +
      5218  vector.data() + vector.size(),
      +
      5219  value,
      +
      5220  CmpLess()) - vector.data();
      +
      5221  VmaVectorInsert(vector, indexToInsert, value);
      +
      5222  return indexToInsert;
      +
      5223 }
      +
      5224 
      +
      5225 template<typename CmpLess, typename VectorT>
      +
      5226 bool VmaVectorRemoveSorted(VectorT& vector, const typename VectorT::value_type& value)
      +
      5227 {
      +
      5228  CmpLess comparator;
      +
      5229  typename VectorT::iterator it = VmaBinaryFindFirstNotLess(
      +
      5230  vector.begin(),
      +
      5231  vector.end(),
      +
      5232  value,
      +
      5233  comparator);
      +
      5234  if((it != vector.end()) && !comparator(*it, value) && !comparator(value, *it))
      +
      5235  {
      +
      5236  size_t indexToRemove = it - vector.begin();
      +
      5237  VmaVectorRemove(vector, indexToRemove);
      +
      5238  return true;
      +
      5239  }
      +
      5240  return false;
      +
      5241 }
      +
      5242 
      +
      5244 // class VmaSmallVector
      +
      5245 
      +
      5246 /*
      +
      5247 This is a vector (a variable-sized array), optimized for the case when the array is small.
      +
      5248 
      +
      5249 It contains some number of elements in-place, which allows it to avoid heap allocation
      +
      5250 when the actual number of elements is below that threshold. This allows normal "small"
      +
      5251 cases to be fast without losing generality for large inputs.
      +
      5252 */
      +
      5253 
      +
      5254 template<typename T, typename AllocatorT, size_t N>
      +
      5255 class VmaSmallVector
      +
      5256 {
      +
      5257 public:
      +
      5258  typedef T value_type;
      +
      5259 
      +
      5260  VmaSmallVector(const AllocatorT& allocator) :
      +
      5261  m_Count(0),
      +
      5262  m_DynamicArray(allocator)
      +
      5263  {
      +
      5264  }
      +
      5265  VmaSmallVector(size_t count, const AllocatorT& allocator) :
      +
      5266  m_Count(count),
      +
      5267  m_DynamicArray(count > N ? count : 0, allocator)
      +
      5268  {
      +
      5269  }
      +
      5270  template<typename SrcT, typename SrcAllocatorT, size_t SrcN>
      +
      5271  VmaSmallVector(const VmaSmallVector<SrcT, SrcAllocatorT, SrcN>& src) = delete;
      +
      5272  template<typename SrcT, typename SrcAllocatorT, size_t SrcN>
      +
      5273  VmaSmallVector<T, AllocatorT, N>& operator=(const VmaSmallVector<SrcT, SrcAllocatorT, SrcN>& rhs) = delete;
      +
      5274 
      +
      5275  bool empty() const { return m_Count == 0; }
      +
      5276  size_t size() const { return m_Count; }
      +
      5277  T* data() { return m_Count > N ? m_DynamicArray.data() : m_StaticArray; }
      +
      5278  const T* data() const { return m_Count > N ? m_DynamicArray.data() : m_StaticArray; }
      +
      5279 
      +
      5280  T& operator[](size_t index)
      +
      5281  {
      +
      5282  VMA_HEAVY_ASSERT(index < m_Count);
      +
      5283  return data()[index];
      +
      5284  }
      +
      5285  const T& operator[](size_t index) const
      +
      5286  {
      +
      5287  VMA_HEAVY_ASSERT(index < m_Count);
      +
      5288  return data()[index];
      +
      5289  }
      +
      5290 
      +
      5291  T& front()
      +
      5292  {
      +
      5293  VMA_HEAVY_ASSERT(m_Count > 0);
      +
      5294  return data()[0];
      +
      5295  }
      +
      5296  const T& front() const
      +
      5297  {
      +
      5298  VMA_HEAVY_ASSERT(m_Count > 0);
      +
      5299  return data()[0];
      +
      5300  }
      +
      5301  T& back()
      +
      5302  {
      +
      5303  VMA_HEAVY_ASSERT(m_Count > 0);
      +
      5304  return data()[m_Count - 1];
      +
      5305  }
      +
      5306  const T& back() const
      +
      5307  {
      +
      5308  VMA_HEAVY_ASSERT(m_Count > 0);
      +
      5309  return data()[m_Count - 1];
      +
      5310  }
      +
      5311 
      +
      5312  void resize(size_t newCount, bool freeMemory = false)
      +
      5313  {
      +
      5314  if(newCount > N && m_Count > N)
      +
      5315  {
      +
      5316  // Any direction, staying in m_DynamicArray
      +
      5317  m_DynamicArray.resize(newCount, freeMemory);
      +
      5318  }
      +
      5319  else if(newCount > N && m_Count <= N)
      +
      5320  {
      +
      5321  // Growing, moving from m_StaticArray to m_DynamicArray
      +
      5322  m_DynamicArray.resize(newCount, freeMemory);
      +
      5323  if(m_Count > 0)
      +
      5324  {
      +
      5325  memcpy(m_DynamicArray.data(), m_StaticArray, m_Count * sizeof(T));
      +
      5326  }
      +
      5327  }
      +
      5328  else if(newCount <= N && m_Count > N)
      +
      5329  {
      +
      5330  // Shrinking, moving from m_DynamicArray to m_StaticArray
      +
      5331  if(newCount > 0)
      +
      5332  {
      +
      5333  memcpy(m_StaticArray, m_DynamicArray.data(), newCount * sizeof(T));
      +
      5334  }
      +
      5335  m_DynamicArray.resize(0, freeMemory);
      +
      5336  }
      +
      5337  else
      +
      5338  {
      +
      5339  // Any direction, staying in m_StaticArray - nothing to do here
      5340  }
      -
      5341  else
      -
      5342  {
      -
      5343  // Any direction, staying in m_StaticArray - nothing to do here
      -
      5344  }
      -
      5345  m_Count = newCount;
      -
      5346  }
      -
      5347 
      -
      5348  void clear(bool freeMemory = false)
      -
      5349  {
      -
      5350  m_DynamicArray.clear(freeMemory);
      -
      5351  m_Count = 0;
      -
      5352  }
      -
      5353 
      -
      5354  void insert(size_t index, const T& src)
      -
      5355  {
      -
      5356  VMA_HEAVY_ASSERT(index <= m_Count);
      -
      5357  const size_t oldCount = size();
      -
      5358  resize(oldCount + 1);
      -
      5359  T* const dataPtr = data();
      -
      5360  if(index < oldCount)
      -
      5361  {
      -
      5362  // I know, this could be more optimal for case where memmove can be memcpy directly from m_StaticArray to m_DynamicArray.
      -
      5363  memmove(dataPtr + (index + 1), dataPtr + index, (oldCount - index) * sizeof(T));
      -
      5364  }
      -
      5365  dataPtr[index] = src;
      -
      5366  }
      -
      5367 
      -
      5368  void remove(size_t index)
      -
      5369  {
      -
      5370  VMA_HEAVY_ASSERT(index < m_Count);
      -
      5371  const size_t oldCount = size();
      -
      5372  if(index < oldCount - 1)
      -
      5373  {
      -
      5374  // I know, this could be more optimal for case where memmove can be memcpy directly from m_DynamicArray to m_StaticArray.
      -
      5375  T* const dataPtr = data();
      -
      5376  memmove(dataPtr + index, dataPtr + (index + 1), (oldCount - index - 1) * sizeof(T));
      -
      5377  }
      -
      5378  resize(oldCount - 1);
      -
      5379  }
      -
      5380 
      -
      5381  void push_back(const T& src)
      -
      5382  {
      -
      5383  const size_t newIndex = size();
      -
      5384  resize(newIndex + 1);
      -
      5385  data()[newIndex] = src;
      -
      5386  }
      -
      5387 
      -
      5388  void pop_back()
      -
      5389  {
      -
      5390  VMA_HEAVY_ASSERT(m_Count > 0);
      -
      5391  resize(size() - 1);
      -
      5392  }
      -
      5393 
      -
      5394  void push_front(const T& src)
      -
      5395  {
      -
      5396  insert(0, src);
      -
      5397  }
      -
      5398 
      -
      5399  void pop_front()
      -
      5400  {
      -
      5401  VMA_HEAVY_ASSERT(m_Count > 0);
      -
      5402  remove(0);
      -
      5403  }
      -
      5404 
      -
      5405  typedef T* iterator;
      -
      5406 
      -
      5407  iterator begin() { return data(); }
      -
      5408  iterator end() { return data() + m_Count; }
      -
      5409 
      -
      5410 private:
      -
      5411  size_t m_Count;
      -
      5412  T m_StaticArray[N]; // Used when m_Size <= N
      -
      5413  VmaVector<T, AllocatorT> m_DynamicArray; // Used when m_Size > N
      -
      5414 };
      -
      5415 
      -
      5417 // class VmaPoolAllocator
      -
      5418 
      -
      5419 /*
      -
      5420 Allocator for objects of type T using a list of arrays (pools) to speed up
      -
      5421 allocation. Number of elements that can be allocated is not bounded because
      -
      5422 allocator can create multiple blocks.
      -
      5423 */
      -
      5424 template<typename T>
      -
      5425 class VmaPoolAllocator
      -
      5426 {
      -
      5427  VMA_CLASS_NO_COPY(VmaPoolAllocator)
      -
      5428 public:
      -
      5429  VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, uint32_t firstBlockCapacity);
      -
      5430  ~VmaPoolAllocator();
      -
      5431  template<typename... Types> T* Alloc(Types... args);
      -
      5432  void Free(T* ptr);
      -
      5433 
      -
      5434 private:
      -
      5435  union Item
      -
      5436  {
      -
      5437  uint32_t NextFreeIndex;
      -
      5438  alignas(T) char Value[sizeof(T)];
      -
      5439  };
      -
      5440 
      -
      5441  struct ItemBlock
      -
      5442  {
      -
      5443  Item* pItems;
      -
      5444  uint32_t Capacity;
      -
      5445  uint32_t FirstFreeIndex;
      -
      5446  };
      +
      5341  m_Count = newCount;
      +
      5342  }
      +
      5343 
      +
      5344  void clear(bool freeMemory = false)
      +
      5345  {
      +
      5346  m_DynamicArray.clear(freeMemory);
      +
      5347  m_Count = 0;
      +
      5348  }
      +
      5349 
      +
      5350  void insert(size_t index, const T& src)
      +
      5351  {
      +
      5352  VMA_HEAVY_ASSERT(index <= m_Count);
      +
      5353  const size_t oldCount = size();
      +
      5354  resize(oldCount + 1);
      +
      5355  T* const dataPtr = data();
      +
      5356  if(index < oldCount)
      +
      5357  {
      +
      5358  // I know, this could be more optimal for case where memmove can be memcpy directly from m_StaticArray to m_DynamicArray.
      +
      5359  memmove(dataPtr + (index + 1), dataPtr + index, (oldCount - index) * sizeof(T));
      +
      5360  }
      +
      5361  dataPtr[index] = src;
      +
      5362  }
      +
      5363 
      +
      5364  void remove(size_t index)
      +
      5365  {
      +
      5366  VMA_HEAVY_ASSERT(index < m_Count);
      +
      5367  const size_t oldCount = size();
      +
      5368  if(index < oldCount - 1)
      +
      5369  {
      +
      5370  // I know, this could be more optimal for case where memmove can be memcpy directly from m_DynamicArray to m_StaticArray.
      +
      5371  T* const dataPtr = data();
      +
      5372  memmove(dataPtr + index, dataPtr + (index + 1), (oldCount - index - 1) * sizeof(T));
      +
      5373  }
      +
      5374  resize(oldCount - 1);
      +
      5375  }
      +
      5376 
      +
      5377  void push_back(const T& src)
      +
      5378  {
      +
      5379  const size_t newIndex = size();
      +
      5380  resize(newIndex + 1);
      +
      5381  data()[newIndex] = src;
      +
      5382  }
      +
      5383 
      +
      5384  void pop_back()
      +
      5385  {
      +
      5386  VMA_HEAVY_ASSERT(m_Count > 0);
      +
      5387  resize(size() - 1);
      +
      5388  }
      +
      5389 
      +
      5390  void push_front(const T& src)
      +
      5391  {
      +
      5392  insert(0, src);
      +
      5393  }
      +
      5394 
      +
      5395  void pop_front()
      +
      5396  {
      +
      5397  VMA_HEAVY_ASSERT(m_Count > 0);
      +
      5398  remove(0);
      +
      5399  }
      +
      5400 
      +
      5401  typedef T* iterator;
      +
      5402 
      +
      5403  iterator begin() { return data(); }
      +
      5404  iterator end() { return data() + m_Count; }
      +
      5405 
      +
      5406 private:
      +
      5407  size_t m_Count;
      +
      5408  T m_StaticArray[N]; // Used when m_Size <= N
      +
      5409  VmaVector<T, AllocatorT> m_DynamicArray; // Used when m_Size > N
      +
      5410 };
      +
      5411 
      +
      5413 // class VmaPoolAllocator
      +
      5414 
      +
      5415 /*
      +
      5416 Allocator for objects of type T using a list of arrays (pools) to speed up
      +
      5417 allocation. Number of elements that can be allocated is not bounded because
      +
      5418 allocator can create multiple blocks.
      +
      5419 */
      +
      5420 template<typename T>
      +
      5421 class VmaPoolAllocator
      +
      5422 {
      +
      5423  VMA_CLASS_NO_COPY(VmaPoolAllocator)
      +
      5424 public:
      +
      5425  VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, uint32_t firstBlockCapacity);
      +
      5426  ~VmaPoolAllocator();
      +
      5427  template<typename... Types> T* Alloc(Types... args);
      +
      5428  void Free(T* ptr);
      +
      5429 
      +
      5430 private:
      +
      5431  union Item
      +
      5432  {
      +
      5433  uint32_t NextFreeIndex;
      +
      5434  alignas(T) char Value[sizeof(T)];
      +
      5435  };
      +
      5436 
      +
      5437  struct ItemBlock
      +
      5438  {
      +
      5439  Item* pItems;
      +
      5440  uint32_t Capacity;
      +
      5441  uint32_t FirstFreeIndex;
      +
      5442  };
      +
      5443 
      +
      5444  const VkAllocationCallbacks* m_pAllocationCallbacks;
      +
      5445  const uint32_t m_FirstBlockCapacity;
      +
      5446  VmaVector< ItemBlock, VmaStlAllocator<ItemBlock> > m_ItemBlocks;
      5447 
      -
      5448  const VkAllocationCallbacks* m_pAllocationCallbacks;
      -
      5449  const uint32_t m_FirstBlockCapacity;
      -
      5450  VmaVector< ItemBlock, VmaStlAllocator<ItemBlock> > m_ItemBlocks;
      -
      5451 
      -
      5452  ItemBlock& CreateNewBlock();
      -
      5453 };
      -
      5454 
      -
      5455 template<typename T>
      -
      5456 VmaPoolAllocator<T>::VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, uint32_t firstBlockCapacity) :
      -
      5457  m_pAllocationCallbacks(pAllocationCallbacks),
      -
      5458  m_FirstBlockCapacity(firstBlockCapacity),
      -
      5459  m_ItemBlocks(VmaStlAllocator<ItemBlock>(pAllocationCallbacks))
      -
      5460 {
      -
      5461  VMA_ASSERT(m_FirstBlockCapacity > 1);
      -
      5462 }
      -
      5463 
      -
      5464 template<typename T>
      -
      5465 VmaPoolAllocator<T>::~VmaPoolAllocator()
      -
      5466 {
      -
      5467  for(size_t i = m_ItemBlocks.size(); i--; )
      -
      5468  vma_delete_array(m_pAllocationCallbacks, m_ItemBlocks[i].pItems, m_ItemBlocks[i].Capacity);
      -
      5469  m_ItemBlocks.clear();
      -
      5470 }
      -
      5471 
      -
      5472 template<typename T>
      -
      5473 template<typename... Types> T* VmaPoolAllocator<T>::Alloc(Types... args)
      -
      5474 {
      -
      5475  for(size_t i = m_ItemBlocks.size(); i--; )
      -
      5476  {
      -
      5477  ItemBlock& block = m_ItemBlocks[i];
      -
      5478  // This block has some free items: Use first one.
      -
      5479  if(block.FirstFreeIndex != UINT32_MAX)
      -
      5480  {
      -
      5481  Item* const pItem = &block.pItems[block.FirstFreeIndex];
      -
      5482  block.FirstFreeIndex = pItem->NextFreeIndex;
      -
      5483  T* result = (T*)&pItem->Value;
      -
      5484  new(result)T(std::forward<Types>(args)...); // Explicit constructor call.
      -
      5485  return result;
      -
      5486  }
      -
      5487  }
      -
      5488 
      -
      5489  // No block has free item: Create new one and use it.
      -
      5490  ItemBlock& newBlock = CreateNewBlock();
      -
      5491  Item* const pItem = &newBlock.pItems[0];
      -
      5492  newBlock.FirstFreeIndex = pItem->NextFreeIndex;
      -
      5493  T* result = (T*)&pItem->Value;
      -
      5494  new(result)T(std::forward<Types>(args)...); // Explicit constructor call.
      -
      5495  return result;
      -
      5496 }
      -
      5497 
      -
      5498 template<typename T>
      -
      5499 void VmaPoolAllocator<T>::Free(T* ptr)
      -
      5500 {
      -
      5501  // Search all memory blocks to find ptr.
      -
      5502  for(size_t i = m_ItemBlocks.size(); i--; )
      -
      5503  {
      -
      5504  ItemBlock& block = m_ItemBlocks[i];
      +
      5448  ItemBlock& CreateNewBlock();
      +
      5449 };
      +
      5450 
      +
      5451 template<typename T>
      +
      5452 VmaPoolAllocator<T>::VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, uint32_t firstBlockCapacity) :
      +
      5453  m_pAllocationCallbacks(pAllocationCallbacks),
      +
      5454  m_FirstBlockCapacity(firstBlockCapacity),
      +
      5455  m_ItemBlocks(VmaStlAllocator<ItemBlock>(pAllocationCallbacks))
      +
      5456 {
      +
      5457  VMA_ASSERT(m_FirstBlockCapacity > 1);
      +
      5458 }
      +
      5459 
      +
      5460 template<typename T>
      +
      5461 VmaPoolAllocator<T>::~VmaPoolAllocator()
      +
      5462 {
      +
      5463  for(size_t i = m_ItemBlocks.size(); i--; )
      +
      5464  vma_delete_array(m_pAllocationCallbacks, m_ItemBlocks[i].pItems, m_ItemBlocks[i].Capacity);
      +
      5465  m_ItemBlocks.clear();
      +
      5466 }
      +
      5467 
      +
      5468 template<typename T>
      +
      5469 template<typename... Types> T* VmaPoolAllocator<T>::Alloc(Types... args)
      +
      5470 {
      +
      5471  for(size_t i = m_ItemBlocks.size(); i--; )
      +
      5472  {
      +
      5473  ItemBlock& block = m_ItemBlocks[i];
      +
      5474  // This block has some free items: Use first one.
      +
      5475  if(block.FirstFreeIndex != UINT32_MAX)
      +
      5476  {
      +
      5477  Item* const pItem = &block.pItems[block.FirstFreeIndex];
      +
      5478  block.FirstFreeIndex = pItem->NextFreeIndex;
      +
      5479  T* result = (T*)&pItem->Value;
      +
      5480  new(result)T(std::forward<Types>(args)...); // Explicit constructor call.
      +
      5481  return result;
      +
      5482  }
      +
      5483  }
      +
      5484 
      +
      5485  // No block has free item: Create new one and use it.
      +
      5486  ItemBlock& newBlock = CreateNewBlock();
      +
      5487  Item* const pItem = &newBlock.pItems[0];
      +
      5488  newBlock.FirstFreeIndex = pItem->NextFreeIndex;
      +
      5489  T* result = (T*)&pItem->Value;
      +
      5490  new(result)T(std::forward<Types>(args)...); // Explicit constructor call.
      +
      5491  return result;
      +
      5492 }
      +
      5493 
      +
      5494 template<typename T>
      +
      5495 void VmaPoolAllocator<T>::Free(T* ptr)
      +
      5496 {
      +
      5497  // Search all memory blocks to find ptr.
      +
      5498  for(size_t i = m_ItemBlocks.size(); i--; )
      +
      5499  {
      +
      5500  ItemBlock& block = m_ItemBlocks[i];
      +
      5501 
      +
      5502  // Casting to union.
      +
      5503  Item* pItemPtr;
      +
      5504  memcpy(&pItemPtr, &ptr, sizeof(pItemPtr));
      5505 
      -
      5506  // Casting to union.
      -
      5507  Item* pItemPtr;
      -
      5508  memcpy(&pItemPtr, &ptr, sizeof(pItemPtr));
      -
      5509 
      -
      5510  // Check if pItemPtr is in address range of this block.
      -
      5511  if((pItemPtr >= block.pItems) && (pItemPtr < block.pItems + block.Capacity))
      -
      5512  {
      -
      5513  ptr->~T(); // Explicit destructor call.
      -
      5514  const uint32_t index = static_cast<uint32_t>(pItemPtr - block.pItems);
      -
      5515  pItemPtr->NextFreeIndex = block.FirstFreeIndex;
      -
      5516  block.FirstFreeIndex = index;
      -
      5517  return;
      -
      5518  }
      -
      5519  }
      -
      5520  VMA_ASSERT(0 && "Pointer doesn't belong to this memory pool.");
      -
      5521 }
      -
      5522 
      -
      5523 template<typename T>
      -
      5524 typename VmaPoolAllocator<T>::ItemBlock& VmaPoolAllocator<T>::CreateNewBlock()
      -
      5525 {
      -
      5526  const uint32_t newBlockCapacity = m_ItemBlocks.empty() ?
      -
      5527  m_FirstBlockCapacity : m_ItemBlocks.back().Capacity * 3 / 2;
      -
      5528 
      -
      5529  const ItemBlock newBlock = {
      -
      5530  vma_new_array(m_pAllocationCallbacks, Item, newBlockCapacity),
      -
      5531  newBlockCapacity,
      -
      5532  0 };
      -
      5533 
      -
      5534  m_ItemBlocks.push_back(newBlock);
      -
      5535 
      -
      5536  // Setup singly-linked list of all free items in this block.
      -
      5537  for(uint32_t i = 0; i < newBlockCapacity - 1; ++i)
      -
      5538  newBlock.pItems[i].NextFreeIndex = i + 1;
      -
      5539  newBlock.pItems[newBlockCapacity - 1].NextFreeIndex = UINT32_MAX;
      -
      5540  return m_ItemBlocks.back();
      -
      5541 }
      -
      5542 
      -
      5544 // class VmaRawList, VmaList
      +
      5506  // Check if pItemPtr is in address range of this block.
      +
      5507  if((pItemPtr >= block.pItems) && (pItemPtr < block.pItems + block.Capacity))
      +
      5508  {
      +
      5509  ptr->~T(); // Explicit destructor call.
      +
      5510  const uint32_t index = static_cast<uint32_t>(pItemPtr - block.pItems);
      +
      5511  pItemPtr->NextFreeIndex = block.FirstFreeIndex;
      +
      5512  block.FirstFreeIndex = index;
      +
      5513  return;
      +
      5514  }
      +
      5515  }
      +
      5516  VMA_ASSERT(0 && "Pointer doesn't belong to this memory pool.");
      +
      5517 }
      +
      5518 
      +
      5519 template<typename T>
      +
      5520 typename VmaPoolAllocator<T>::ItemBlock& VmaPoolAllocator<T>::CreateNewBlock()
      +
      5521 {
      +
      5522  const uint32_t newBlockCapacity = m_ItemBlocks.empty() ?
      +
      5523  m_FirstBlockCapacity : m_ItemBlocks.back().Capacity * 3 / 2;
      +
      5524 
      +
      5525  const ItemBlock newBlock = {
      +
      5526  vma_new_array(m_pAllocationCallbacks, Item, newBlockCapacity),
      +
      5527  newBlockCapacity,
      +
      5528  0 };
      +
      5529 
      +
      5530  m_ItemBlocks.push_back(newBlock);
      +
      5531 
      +
      5532  // Setup singly-linked list of all free items in this block.
      +
      5533  for(uint32_t i = 0; i < newBlockCapacity - 1; ++i)
      +
      5534  newBlock.pItems[i].NextFreeIndex = i + 1;
      +
      5535  newBlock.pItems[newBlockCapacity - 1].NextFreeIndex = UINT32_MAX;
      +
      5536  return m_ItemBlocks.back();
      +
      5537 }
      +
      5538 
      +
      5540 // class VmaRawList, VmaList
      +
      5541 
      +
      5542 #if VMA_USE_STL_LIST
      +
      5543 
      +
      5544 #define VmaList std::list
      5545 
      -
      5546 #if VMA_USE_STL_LIST
      +
      5546 #else // #if VMA_USE_STL_LIST
      5547 
      -
      5548 #define VmaList std::list
      -
      5549 
      -
      5550 #else // #if VMA_USE_STL_LIST
      -
      5551 
      -
      5552 template<typename T>
      -
      5553 struct VmaListItem
      -
      5554 {
      -
      5555  VmaListItem* pPrev;
      -
      5556  VmaListItem* pNext;
      -
      5557  T Value;
      -
      5558 };
      -
      5559 
      -
      5560 // Doubly linked list.
      -
      5561 template<typename T>
      -
      5562 class VmaRawList
      -
      5563 {
      -
      5564  VMA_CLASS_NO_COPY(VmaRawList)
      -
      5565 public:
      -
      5566  typedef VmaListItem<T> ItemType;
      +
      5548 template<typename T>
      +
      5549 struct VmaListItem
      +
      5550 {
      +
      5551  VmaListItem* pPrev;
      +
      5552  VmaListItem* pNext;
      +
      5553  T Value;
      +
      5554 };
      +
      5555 
      +
      5556 // Doubly linked list.
      +
      5557 template<typename T>
      +
      5558 class VmaRawList
      +
      5559 {
      +
      5560  VMA_CLASS_NO_COPY(VmaRawList)
      +
      5561 public:
      +
      5562  typedef VmaListItem<T> ItemType;
      +
      5563 
      +
      5564  VmaRawList(const VkAllocationCallbacks* pAllocationCallbacks);
      +
      5565  ~VmaRawList();
      +
      5566  void Clear();
      5567 
      -
      5568  VmaRawList(const VkAllocationCallbacks* pAllocationCallbacks);
      -
      5569  ~VmaRawList();
      -
      5570  void Clear();
      -
      5571 
      -
      5572  size_t GetCount() const { return m_Count; }
      -
      5573  bool IsEmpty() const { return m_Count == 0; }
      -
      5574 
      -
      5575  ItemType* Front() { return m_pFront; }
      -
      5576  const ItemType* Front() const { return m_pFront; }
      -
      5577  ItemType* Back() { return m_pBack; }
      -
      5578  const ItemType* Back() const { return m_pBack; }
      -
      5579 
      -
      5580  ItemType* PushBack();
      -
      5581  ItemType* PushFront();
      -
      5582  ItemType* PushBack(const T& value);
      -
      5583  ItemType* PushFront(const T& value);
      -
      5584  void PopBack();
      -
      5585  void PopFront();
      -
      5586 
      -
      5587  // Item can be null - it means PushBack.
      -
      5588  ItemType* InsertBefore(ItemType* pItem);
      -
      5589  // Item can be null - it means PushFront.
      -
      5590  ItemType* InsertAfter(ItemType* pItem);
      -
      5591 
      -
      5592  ItemType* InsertBefore(ItemType* pItem, const T& value);
      -
      5593  ItemType* InsertAfter(ItemType* pItem, const T& value);
      -
      5594 
      -
      5595  void Remove(ItemType* pItem);
      -
      5596 
      -
      5597 private:
      -
      5598  const VkAllocationCallbacks* const m_pAllocationCallbacks;
      -
      5599  VmaPoolAllocator<ItemType> m_ItemAllocator;
      -
      5600  ItemType* m_pFront;
      -
      5601  ItemType* m_pBack;
      -
      5602  size_t m_Count;
      -
      5603 };
      -
      5604 
      -
      5605 template<typename T>
      -
      5606 VmaRawList<T>::VmaRawList(const VkAllocationCallbacks* pAllocationCallbacks) :
      -
      5607  m_pAllocationCallbacks(pAllocationCallbacks),
      -
      5608  m_ItemAllocator(pAllocationCallbacks, 128),
      -
      5609  m_pFront(VMA_NULL),
      -
      5610  m_pBack(VMA_NULL),
      -
      5611  m_Count(0)
      -
      5612 {
      -
      5613 }
      -
      5614 
      -
      5615 template<typename T>
      -
      5616 VmaRawList<T>::~VmaRawList()
      -
      5617 {
      -
      5618  // Intentionally not calling Clear, because that would be unnecessary
      -
      5619  // computations to return all items to m_ItemAllocator as free.
      -
      5620 }
      -
      5621 
      -
      5622 template<typename T>
      -
      5623 void VmaRawList<T>::Clear()
      -
      5624 {
      -
      5625  if(IsEmpty() == false)
      -
      5626  {
      -
      5627  ItemType* pItem = m_pBack;
      -
      5628  while(pItem != VMA_NULL)
      -
      5629  {
      -
      5630  ItemType* const pPrevItem = pItem->pPrev;
      -
      5631  m_ItemAllocator.Free(pItem);
      -
      5632  pItem = pPrevItem;
      -
      5633  }
      -
      5634  m_pFront = VMA_NULL;
      -
      5635  m_pBack = VMA_NULL;
      -
      5636  m_Count = 0;
      -
      5637  }
      -
      5638 }
      -
      5639 
      -
      5640 template<typename T>
      -
      5641 VmaListItem<T>* VmaRawList<T>::PushBack()
      -
      5642 {
      -
      5643  ItemType* const pNewItem = m_ItemAllocator.Alloc();
      -
      5644  pNewItem->pNext = VMA_NULL;
      -
      5645  if(IsEmpty())
      -
      5646  {
      -
      5647  pNewItem->pPrev = VMA_NULL;
      -
      5648  m_pFront = pNewItem;
      -
      5649  m_pBack = pNewItem;
      -
      5650  m_Count = 1;
      -
      5651  }
      -
      5652  else
      -
      5653  {
      -
      5654  pNewItem->pPrev = m_pBack;
      -
      5655  m_pBack->pNext = pNewItem;
      -
      5656  m_pBack = pNewItem;
      -
      5657  ++m_Count;
      -
      5658  }
      -
      5659  return pNewItem;
      -
      5660 }
      -
      5661 
      -
      5662 template<typename T>
      -
      5663 VmaListItem<T>* VmaRawList<T>::PushFront()
      -
      5664 {
      -
      5665  ItemType* const pNewItem = m_ItemAllocator.Alloc();
      -
      5666  pNewItem->pPrev = VMA_NULL;
      -
      5667  if(IsEmpty())
      -
      5668  {
      -
      5669  pNewItem->pNext = VMA_NULL;
      -
      5670  m_pFront = pNewItem;
      -
      5671  m_pBack = pNewItem;
      -
      5672  m_Count = 1;
      -
      5673  }
      -
      5674  else
      -
      5675  {
      -
      5676  pNewItem->pNext = m_pFront;
      -
      5677  m_pFront->pPrev = pNewItem;
      -
      5678  m_pFront = pNewItem;
      -
      5679  ++m_Count;
      -
      5680  }
      -
      5681  return pNewItem;
      -
      5682 }
      -
      5683 
      -
      5684 template<typename T>
      -
      5685 VmaListItem<T>* VmaRawList<T>::PushBack(const T& value)
      -
      5686 {
      -
      5687  ItemType* const pNewItem = PushBack();
      -
      5688  pNewItem->Value = value;
      -
      5689  return pNewItem;
      -
      5690 }
      -
      5691 
      -
      5692 template<typename T>
      -
      5693 VmaListItem<T>* VmaRawList<T>::PushFront(const T& value)
      -
      5694 {
      -
      5695  ItemType* const pNewItem = PushFront();
      -
      5696  pNewItem->Value = value;
      -
      5697  return pNewItem;
      -
      5698 }
      -
      5699 
      -
      5700 template<typename T>
      -
      5701 void VmaRawList<T>::PopBack()
      -
      5702 {
      -
      5703  VMA_HEAVY_ASSERT(m_Count > 0);
      -
      5704  ItemType* const pBackItem = m_pBack;
      -
      5705  ItemType* const pPrevItem = pBackItem->pPrev;
      -
      5706  if(pPrevItem != VMA_NULL)
      -
      5707  {
      -
      5708  pPrevItem->pNext = VMA_NULL;
      -
      5709  }
      -
      5710  m_pBack = pPrevItem;
      -
      5711  m_ItemAllocator.Free(pBackItem);
      -
      5712  --m_Count;
      -
      5713 }
      -
      5714 
      -
      5715 template<typename T>
      -
      5716 void VmaRawList<T>::PopFront()
      -
      5717 {
      -
      5718  VMA_HEAVY_ASSERT(m_Count > 0);
      -
      5719  ItemType* const pFrontItem = m_pFront;
      -
      5720  ItemType* const pNextItem = pFrontItem->pNext;
      -
      5721  if(pNextItem != VMA_NULL)
      -
      5722  {
      -
      5723  pNextItem->pPrev = VMA_NULL;
      -
      5724  }
      -
      5725  m_pFront = pNextItem;
      -
      5726  m_ItemAllocator.Free(pFrontItem);
      -
      5727  --m_Count;
      -
      5728 }
      -
      5729 
      -
      5730 template<typename T>
      -
      5731 void VmaRawList<T>::Remove(ItemType* pItem)
      -
      5732 {
      -
      5733  VMA_HEAVY_ASSERT(pItem != VMA_NULL);
      -
      5734  VMA_HEAVY_ASSERT(m_Count > 0);
      -
      5735 
      -
      5736  if(pItem->pPrev != VMA_NULL)
      +
      5568  size_t GetCount() const { return m_Count; }
      +
      5569  bool IsEmpty() const { return m_Count == 0; }
      +
      5570 
      +
      5571  ItemType* Front() { return m_pFront; }
      +
      5572  const ItemType* Front() const { return m_pFront; }
      +
      5573  ItemType* Back() { return m_pBack; }
      +
      5574  const ItemType* Back() const { return m_pBack; }
      +
      5575 
      +
      5576  ItemType* PushBack();
      +
      5577  ItemType* PushFront();
      +
      5578  ItemType* PushBack(const T& value);
      +
      5579  ItemType* PushFront(const T& value);
      +
      5580  void PopBack();
      +
      5581  void PopFront();
      +
      5582 
      +
      5583  // Item can be null - it means PushBack.
      +
      5584  ItemType* InsertBefore(ItemType* pItem);
      +
      5585  // Item can be null - it means PushFront.
      +
      5586  ItemType* InsertAfter(ItemType* pItem);
      +
      5587 
      +
      5588  ItemType* InsertBefore(ItemType* pItem, const T& value);
      +
      5589  ItemType* InsertAfter(ItemType* pItem, const T& value);
      +
      5590 
      +
      5591  void Remove(ItemType* pItem);
      +
      5592 
      +
      5593 private:
      +
      5594  const VkAllocationCallbacks* const m_pAllocationCallbacks;
      +
      5595  VmaPoolAllocator<ItemType> m_ItemAllocator;
      +
      5596  ItemType* m_pFront;
      +
      5597  ItemType* m_pBack;
      +
      5598  size_t m_Count;
      +
      5599 };
      +
      5600 
      +
      5601 template<typename T>
      +
      5602 VmaRawList<T>::VmaRawList(const VkAllocationCallbacks* pAllocationCallbacks) :
      +
      5603  m_pAllocationCallbacks(pAllocationCallbacks),
      +
      5604  m_ItemAllocator(pAllocationCallbacks, 128),
      +
      5605  m_pFront(VMA_NULL),
      +
      5606  m_pBack(VMA_NULL),
      +
      5607  m_Count(0)
      +
      5608 {
      +
      5609 }
      +
      5610 
      +
      5611 template<typename T>
      +
      5612 VmaRawList<T>::~VmaRawList()
      +
      5613 {
      +
      5614  // Intentionally not calling Clear, because that would be unnecessary
      +
      5615  // computations to return all items to m_ItemAllocator as free.
      +
      5616 }
      +
      5617 
      +
      5618 template<typename T>
      +
      5619 void VmaRawList<T>::Clear()
      +
      5620 {
      +
      5621  if(IsEmpty() == false)
      +
      5622  {
      +
      5623  ItemType* pItem = m_pBack;
      +
      5624  while(pItem != VMA_NULL)
      +
      5625  {
      +
      5626  ItemType* const pPrevItem = pItem->pPrev;
      +
      5627  m_ItemAllocator.Free(pItem);
      +
      5628  pItem = pPrevItem;
      +
      5629  }
      +
      5630  m_pFront = VMA_NULL;
      +
      5631  m_pBack = VMA_NULL;
      +
      5632  m_Count = 0;
      +
      5633  }
      +
      5634 }
      +
      5635 
      +
      5636 template<typename T>
      +
      5637 VmaListItem<T>* VmaRawList<T>::PushBack()
      +
      5638 {
      +
      5639  ItemType* const pNewItem = m_ItemAllocator.Alloc();
      +
      5640  pNewItem->pNext = VMA_NULL;
      +
      5641  if(IsEmpty())
      +
      5642  {
      +
      5643  pNewItem->pPrev = VMA_NULL;
      +
      5644  m_pFront = pNewItem;
      +
      5645  m_pBack = pNewItem;
      +
      5646  m_Count = 1;
      +
      5647  }
      +
      5648  else
      +
      5649  {
      +
      5650  pNewItem->pPrev = m_pBack;
      +
      5651  m_pBack->pNext = pNewItem;
      +
      5652  m_pBack = pNewItem;
      +
      5653  ++m_Count;
      +
      5654  }
      +
      5655  return pNewItem;
      +
      5656 }
      +
      5657 
      +
      5658 template<typename T>
      +
      5659 VmaListItem<T>* VmaRawList<T>::PushFront()
      +
      5660 {
      +
      5661  ItemType* const pNewItem = m_ItemAllocator.Alloc();
      +
      5662  pNewItem->pPrev = VMA_NULL;
      +
      5663  if(IsEmpty())
      +
      5664  {
      +
      5665  pNewItem->pNext = VMA_NULL;
      +
      5666  m_pFront = pNewItem;
      +
      5667  m_pBack = pNewItem;
      +
      5668  m_Count = 1;
      +
      5669  }
      +
      5670  else
      +
      5671  {
      +
      5672  pNewItem->pNext = m_pFront;
      +
      5673  m_pFront->pPrev = pNewItem;
      +
      5674  m_pFront = pNewItem;
      +
      5675  ++m_Count;
      +
      5676  }
      +
      5677  return pNewItem;
      +
      5678 }
      +
      5679 
      +
      5680 template<typename T>
      +
      5681 VmaListItem<T>* VmaRawList<T>::PushBack(const T& value)
      +
      5682 {
      +
      5683  ItemType* const pNewItem = PushBack();
      +
      5684  pNewItem->Value = value;
      +
      5685  return pNewItem;
      +
      5686 }
      +
      5687 
      +
      5688 template<typename T>
      +
      5689 VmaListItem<T>* VmaRawList<T>::PushFront(const T& value)
      +
      5690 {
      +
      5691  ItemType* const pNewItem = PushFront();
      +
      5692  pNewItem->Value = value;
      +
      5693  return pNewItem;
      +
      5694 }
      +
      5695 
      +
      5696 template<typename T>
      +
      5697 void VmaRawList<T>::PopBack()
      +
      5698 {
      +
      5699  VMA_HEAVY_ASSERT(m_Count > 0);
      +
      5700  ItemType* const pBackItem = m_pBack;
      +
      5701  ItemType* const pPrevItem = pBackItem->pPrev;
      +
      5702  if(pPrevItem != VMA_NULL)
      +
      5703  {
      +
      5704  pPrevItem->pNext = VMA_NULL;
      +
      5705  }
      +
      5706  m_pBack = pPrevItem;
      +
      5707  m_ItemAllocator.Free(pBackItem);
      +
      5708  --m_Count;
      +
      5709 }
      +
      5710 
      +
      5711 template<typename T>
      +
      5712 void VmaRawList<T>::PopFront()
      +
      5713 {
      +
      5714  VMA_HEAVY_ASSERT(m_Count > 0);
      +
      5715  ItemType* const pFrontItem = m_pFront;
      +
      5716  ItemType* const pNextItem = pFrontItem->pNext;
      +
      5717  if(pNextItem != VMA_NULL)
      +
      5718  {
      +
      5719  pNextItem->pPrev = VMA_NULL;
      +
      5720  }
      +
      5721  m_pFront = pNextItem;
      +
      5722  m_ItemAllocator.Free(pFrontItem);
      +
      5723  --m_Count;
      +
      5724 }
      +
      5725 
      +
      5726 template<typename T>
      +
      5727 void VmaRawList<T>::Remove(ItemType* pItem)
      +
      5728 {
      +
      5729  VMA_HEAVY_ASSERT(pItem != VMA_NULL);
      +
      5730  VMA_HEAVY_ASSERT(m_Count > 0);
      +
      5731 
      +
      5732  if(pItem->pPrev != VMA_NULL)
      +
      5733  {
      +
      5734  pItem->pPrev->pNext = pItem->pNext;
      +
      5735  }
      +
      5736  else
      5737  {
      -
      5738  pItem->pPrev->pNext = pItem->pNext;
      -
      5739  }
      -
      5740  else
      -
      5741  {
      -
      5742  VMA_HEAVY_ASSERT(m_pFront == pItem);
      -
      5743  m_pFront = pItem->pNext;
      -
      5744  }
      -
      5745 
      -
      5746  if(pItem->pNext != VMA_NULL)
      +
      5738  VMA_HEAVY_ASSERT(m_pFront == pItem);
      +
      5739  m_pFront = pItem->pNext;
      +
      5740  }
      +
      5741 
      +
      5742  if(pItem->pNext != VMA_NULL)
      +
      5743  {
      +
      5744  pItem->pNext->pPrev = pItem->pPrev;
      +
      5745  }
      +
      5746  else
      5747  {
      -
      5748  pItem->pNext->pPrev = pItem->pPrev;
      -
      5749  }
      -
      5750  else
      -
      5751  {
      -
      5752  VMA_HEAVY_ASSERT(m_pBack == pItem);
      -
      5753  m_pBack = pItem->pPrev;
      -
      5754  }
      +
      5748  VMA_HEAVY_ASSERT(m_pBack == pItem);
      +
      5749  m_pBack = pItem->pPrev;
      +
      5750  }
      +
      5751 
      +
      5752  m_ItemAllocator.Free(pItem);
      +
      5753  --m_Count;
      +
      5754 }
      5755 
      -
      5756  m_ItemAllocator.Free(pItem);
      -
      5757  --m_Count;
      -
      5758 }
      -
      5759 
      -
      5760 template<typename T>
      -
      5761 VmaListItem<T>* VmaRawList<T>::InsertBefore(ItemType* pItem)
      -
      5762 {
      -
      5763  if(pItem != VMA_NULL)
      -
      5764  {
      -
      5765  ItemType* const prevItem = pItem->pPrev;
      -
      5766  ItemType* const newItem = m_ItemAllocator.Alloc();
      -
      5767  newItem->pPrev = prevItem;
      -
      5768  newItem->pNext = pItem;
      -
      5769  pItem->pPrev = newItem;
      -
      5770  if(prevItem != VMA_NULL)
      +
      5756 template<typename T>
      +
      5757 VmaListItem<T>* VmaRawList<T>::InsertBefore(ItemType* pItem)
      +
      5758 {
      +
      5759  if(pItem != VMA_NULL)
      +
      5760  {
      +
      5761  ItemType* const prevItem = pItem->pPrev;
      +
      5762  ItemType* const newItem = m_ItemAllocator.Alloc();
      +
      5763  newItem->pPrev = prevItem;
      +
      5764  newItem->pNext = pItem;
      +
      5765  pItem->pPrev = newItem;
      +
      5766  if(prevItem != VMA_NULL)
      +
      5767  {
      +
      5768  prevItem->pNext = newItem;
      +
      5769  }
      +
      5770  else
      5771  {
      -
      5772  prevItem->pNext = newItem;
      -
      5773  }
      -
      5774  else
      -
      5775  {
      -
      5776  VMA_HEAVY_ASSERT(m_pFront == pItem);
      -
      5777  m_pFront = newItem;
      -
      5778  }
      -
      5779  ++m_Count;
      -
      5780  return newItem;
      -
      5781  }
      -
      5782  else
      -
      5783  return PushBack();
      -
      5784 }
      -
      5785 
      -
      5786 template<typename T>
      -
      5787 VmaListItem<T>* VmaRawList<T>::InsertAfter(ItemType* pItem)
      -
      5788 {
      -
      5789  if(pItem != VMA_NULL)
      -
      5790  {
      -
      5791  ItemType* const nextItem = pItem->pNext;
      -
      5792  ItemType* const newItem = m_ItemAllocator.Alloc();
      -
      5793  newItem->pNext = nextItem;
      -
      5794  newItem->pPrev = pItem;
      -
      5795  pItem->pNext = newItem;
      -
      5796  if(nextItem != VMA_NULL)
      +
      5772  VMA_HEAVY_ASSERT(m_pFront == pItem);
      +
      5773  m_pFront = newItem;
      +
      5774  }
      +
      5775  ++m_Count;
      +
      5776  return newItem;
      +
      5777  }
      +
      5778  else
      +
      5779  return PushBack();
      +
      5780 }
      +
      5781 
      +
      5782 template<typename T>
      +
      5783 VmaListItem<T>* VmaRawList<T>::InsertAfter(ItemType* pItem)
      +
      5784 {
      +
      5785  if(pItem != VMA_NULL)
      +
      5786  {
      +
      5787  ItemType* const nextItem = pItem->pNext;
      +
      5788  ItemType* const newItem = m_ItemAllocator.Alloc();
      +
      5789  newItem->pNext = nextItem;
      +
      5790  newItem->pPrev = pItem;
      +
      5791  pItem->pNext = newItem;
      +
      5792  if(nextItem != VMA_NULL)
      +
      5793  {
      +
      5794  nextItem->pPrev = newItem;
      +
      5795  }
      +
      5796  else
      5797  {
      -
      5798  nextItem->pPrev = newItem;
      -
      5799  }
      -
      5800  else
      -
      5801  {
      -
      5802  VMA_HEAVY_ASSERT(m_pBack == pItem);
      -
      5803  m_pBack = newItem;
      -
      5804  }
      -
      5805  ++m_Count;
      -
      5806  return newItem;
      -
      5807  }
      -
      5808  else
      -
      5809  return PushFront();
      -
      5810 }
      -
      5811 
      -
      5812 template<typename T>
      -
      5813 VmaListItem<T>* VmaRawList<T>::InsertBefore(ItemType* pItem, const T& value)
      -
      5814 {
      -
      5815  ItemType* const newItem = InsertBefore(pItem);
      -
      5816  newItem->Value = value;
      -
      5817  return newItem;
      -
      5818 }
      -
      5819 
      -
      5820 template<typename T>
      -
      5821 VmaListItem<T>* VmaRawList<T>::InsertAfter(ItemType* pItem, const T& value)
      -
      5822 {
      -
      5823  ItemType* const newItem = InsertAfter(pItem);
      -
      5824  newItem->Value = value;
      -
      5825  return newItem;
      -
      5826 }
      -
      5827 
      -
      5828 template<typename T, typename AllocatorT>
      -
      5829 class VmaList
      -
      5830 {
      -
      5831  VMA_CLASS_NO_COPY(VmaList)
      -
      5832 public:
      -
      5833  class iterator
      -
      5834  {
      -
      5835  public:
      -
      5836  iterator() :
      -
      5837  m_pList(VMA_NULL),
      -
      5838  m_pItem(VMA_NULL)
      -
      5839  {
      -
      5840  }
      -
      5841 
      -
      5842  T& operator*() const
      -
      5843  {
      -
      5844  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
      -
      5845  return m_pItem->Value;
      -
      5846  }
      -
      5847  T* operator->() const
      -
      5848  {
      -
      5849  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
      -
      5850  return &m_pItem->Value;
      -
      5851  }
      -
      5852 
      -
      5853  iterator& operator++()
      -
      5854  {
      -
      5855  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
      -
      5856  m_pItem = m_pItem->pNext;
      -
      5857  return *this;
      -
      5858  }
      -
      5859  iterator& operator--()
      -
      5860  {
      -
      5861  if(m_pItem != VMA_NULL)
      +
      5798  VMA_HEAVY_ASSERT(m_pBack == pItem);
      +
      5799  m_pBack = newItem;
      +
      5800  }
      +
      5801  ++m_Count;
      +
      5802  return newItem;
      +
      5803  }
      +
      5804  else
      +
      5805  return PushFront();
      +
      5806 }
      +
      5807 
      +
      5808 template<typename T>
      +
      5809 VmaListItem<T>* VmaRawList<T>::InsertBefore(ItemType* pItem, const T& value)
      +
      5810 {
      +
      5811  ItemType* const newItem = InsertBefore(pItem);
      +
      5812  newItem->Value = value;
      +
      5813  return newItem;
      +
      5814 }
      +
      5815 
      +
      5816 template<typename T>
      +
      5817 VmaListItem<T>* VmaRawList<T>::InsertAfter(ItemType* pItem, const T& value)
      +
      5818 {
      +
      5819  ItemType* const newItem = InsertAfter(pItem);
      +
      5820  newItem->Value = value;
      +
      5821  return newItem;
      +
      5822 }
      +
      5823 
      +
      5824 template<typename T, typename AllocatorT>
      +
      5825 class VmaList
      +
      5826 {
      +
      5827  VMA_CLASS_NO_COPY(VmaList)
      +
      5828 public:
      +
      5829  class iterator
      +
      5830  {
      +
      5831  public:
      +
      5832  iterator() :
      +
      5833  m_pList(VMA_NULL),
      +
      5834  m_pItem(VMA_NULL)
      +
      5835  {
      +
      5836  }
      +
      5837 
      +
      5838  T& operator*() const
      +
      5839  {
      +
      5840  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
      +
      5841  return m_pItem->Value;
      +
      5842  }
      +
      5843  T* operator->() const
      +
      5844  {
      +
      5845  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
      +
      5846  return &m_pItem->Value;
      +
      5847  }
      +
      5848 
      +
      5849  iterator& operator++()
      +
      5850  {
      +
      5851  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
      +
      5852  m_pItem = m_pItem->pNext;
      +
      5853  return *this;
      +
      5854  }
      +
      5855  iterator& operator--()
      +
      5856  {
      +
      5857  if(m_pItem != VMA_NULL)
      +
      5858  {
      +
      5859  m_pItem = m_pItem->pPrev;
      +
      5860  }
      +
      5861  else
      5862  {
      -
      5863  m_pItem = m_pItem->pPrev;
      -
      5864  }
      -
      5865  else
      -
      5866  {
      -
      5867  VMA_HEAVY_ASSERT(!m_pList->IsEmpty());
      -
      5868  m_pItem = m_pList->Back();
      -
      5869  }
      -
      5870  return *this;
      -
      5871  }
      -
      5872 
      -
      5873  iterator operator++(int)
      -
      5874  {
      -
      5875  iterator result = *this;
      -
      5876  ++*this;
      -
      5877  return result;
      -
      5878  }
      -
      5879  iterator operator--(int)
      -
      5880  {
      -
      5881  iterator result = *this;
      -
      5882  --*this;
      -
      5883  return result;
      -
      5884  }
      -
      5885 
      -
      5886  bool operator==(const iterator& rhs) const
      -
      5887  {
      -
      5888  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
      -
      5889  return m_pItem == rhs.m_pItem;
      -
      5890  }
      -
      5891  bool operator!=(const iterator& rhs) const
      -
      5892  {
      -
      5893  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
      -
      5894  return m_pItem != rhs.m_pItem;
      -
      5895  }
      +
      5863  VMA_HEAVY_ASSERT(!m_pList->IsEmpty());
      +
      5864  m_pItem = m_pList->Back();
      +
      5865  }
      +
      5866  return *this;
      +
      5867  }
      +
      5868 
      +
      5869  iterator operator++(int)
      +
      5870  {
      +
      5871  iterator result = *this;
      +
      5872  ++*this;
      +
      5873  return result;
      +
      5874  }
      +
      5875  iterator operator--(int)
      +
      5876  {
      +
      5877  iterator result = *this;
      +
      5878  --*this;
      +
      5879  return result;
      +
      5880  }
      +
      5881 
      +
      5882  bool operator==(const iterator& rhs) const
      +
      5883  {
      +
      5884  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
      +
      5885  return m_pItem == rhs.m_pItem;
      +
      5886  }
      +
      5887  bool operator!=(const iterator& rhs) const
      +
      5888  {
      +
      5889  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
      +
      5890  return m_pItem != rhs.m_pItem;
      +
      5891  }
      +
      5892 
      +
      5893  private:
      +
      5894  VmaRawList<T>* m_pList;
      +
      5895  VmaListItem<T>* m_pItem;
      5896 
      -
      5897  private:
      -
      5898  VmaRawList<T>* m_pList;
      -
      5899  VmaListItem<T>* m_pItem;
      -
      5900 
      -
      5901  iterator(VmaRawList<T>* pList, VmaListItem<T>* pItem) :
      -
      5902  m_pList(pList),
      -
      5903  m_pItem(pItem)
      -
      5904  {
      -
      5905  }
      -
      5906 
      -
      5907  friend class VmaList<T, AllocatorT>;
      -
      5908  };
      -
      5909 
      -
      5910  class const_iterator
      -
      5911  {
      -
      5912  public:
      -
      5913  const_iterator() :
      -
      5914  m_pList(VMA_NULL),
      -
      5915  m_pItem(VMA_NULL)
      -
      5916  {
      -
      5917  }
      -
      5918 
      -
      5919  const_iterator(const iterator& src) :
      -
      5920  m_pList(src.m_pList),
      -
      5921  m_pItem(src.m_pItem)
      -
      5922  {
      -
      5923  }
      -
      5924 
      -
      5925  const T& operator*() const
      -
      5926  {
      -
      5927  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
      -
      5928  return m_pItem->Value;
      -
      5929  }
      -
      5930  const T* operator->() const
      -
      5931  {
      -
      5932  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
      -
      5933  return &m_pItem->Value;
      -
      5934  }
      -
      5935 
      -
      5936  const_iterator& operator++()
      -
      5937  {
      -
      5938  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
      -
      5939  m_pItem = m_pItem->pNext;
      -
      5940  return *this;
      -
      5941  }
      -
      5942  const_iterator& operator--()
      -
      5943  {
      -
      5944  if(m_pItem != VMA_NULL)
      +
      5897  iterator(VmaRawList<T>* pList, VmaListItem<T>* pItem) :
      +
      5898  m_pList(pList),
      +
      5899  m_pItem(pItem)
      +
      5900  {
      +
      5901  }
      +
      5902 
      +
      5903  friend class VmaList<T, AllocatorT>;
      +
      5904  };
      +
      5905 
      +
      5906  class const_iterator
      +
      5907  {
      +
      5908  public:
      +
      5909  const_iterator() :
      +
      5910  m_pList(VMA_NULL),
      +
      5911  m_pItem(VMA_NULL)
      +
      5912  {
      +
      5913  }
      +
      5914 
      +
      5915  const_iterator(const iterator& src) :
      +
      5916  m_pList(src.m_pList),
      +
      5917  m_pItem(src.m_pItem)
      +
      5918  {
      +
      5919  }
      +
      5920 
      +
      5921  const T& operator*() const
      +
      5922  {
      +
      5923  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
      +
      5924  return m_pItem->Value;
      +
      5925  }
      +
      5926  const T* operator->() const
      +
      5927  {
      +
      5928  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
      +
      5929  return &m_pItem->Value;
      +
      5930  }
      +
      5931 
      +
      5932  const_iterator& operator++()
      +
      5933  {
      +
      5934  VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
      +
      5935  m_pItem = m_pItem->pNext;
      +
      5936  return *this;
      +
      5937  }
      +
      5938  const_iterator& operator--()
      +
      5939  {
      +
      5940  if(m_pItem != VMA_NULL)
      +
      5941  {
      +
      5942  m_pItem = m_pItem->pPrev;
      +
      5943  }
      +
      5944  else
      5945  {
      -
      5946  m_pItem = m_pItem->pPrev;
      -
      5947  }
      -
      5948  else
      -
      5949  {
      -
      5950  VMA_HEAVY_ASSERT(!m_pList->IsEmpty());
      -
      5951  m_pItem = m_pList->Back();
      -
      5952  }
      -
      5953  return *this;
      -
      5954  }
      -
      5955 
      -
      5956  const_iterator operator++(int)
      -
      5957  {
      -
      5958  const_iterator result = *this;
      -
      5959  ++*this;
      -
      5960  return result;
      -
      5961  }
      -
      5962  const_iterator operator--(int)
      -
      5963  {
      -
      5964  const_iterator result = *this;
      -
      5965  --*this;
      -
      5966  return result;
      -
      5967  }
      -
      5968 
      -
      5969  bool operator==(const const_iterator& rhs) const
      -
      5970  {
      -
      5971  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
      -
      5972  return m_pItem == rhs.m_pItem;
      -
      5973  }
      -
      5974  bool operator!=(const const_iterator& rhs) const
      -
      5975  {
      -
      5976  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
      -
      5977  return m_pItem != rhs.m_pItem;
      -
      5978  }
      -
      5979 
      -
      5980  private:
      -
      5981  const_iterator(const VmaRawList<T>* pList, const VmaListItem<T>* pItem) :
      -
      5982  m_pList(pList),
      -
      5983  m_pItem(pItem)
      -
      5984  {
      -
      5985  }
      -
      5986 
      -
      5987  const VmaRawList<T>* m_pList;
      -
      5988  const VmaListItem<T>* m_pItem;
      -
      5989 
      -
      5990  friend class VmaList<T, AllocatorT>;
      -
      5991  };
      -
      5992 
      -
      5993  VmaList(const AllocatorT& allocator) : m_RawList(allocator.m_pCallbacks) { }
      -
      5994 
      -
      5995  bool empty() const { return m_RawList.IsEmpty(); }
      -
      5996  size_t size() const { return m_RawList.GetCount(); }
      -
      5997 
      -
      5998  iterator begin() { return iterator(&m_RawList, m_RawList.Front()); }
      -
      5999  iterator end() { return iterator(&m_RawList, VMA_NULL); }
      -
      6000 
      -
      6001  const_iterator cbegin() const { return const_iterator(&m_RawList, m_RawList.Front()); }
      -
      6002  const_iterator cend() const { return const_iterator(&m_RawList, VMA_NULL); }
      -
      6003 
      -
      6004  void clear() { m_RawList.Clear(); }
      -
      6005  void push_back(const T& value) { m_RawList.PushBack(value); }
      -
      6006  void erase(iterator it) { m_RawList.Remove(it.m_pItem); }
      -
      6007  iterator insert(iterator it, const T& value) { return iterator(&m_RawList, m_RawList.InsertBefore(it.m_pItem, value)); }
      +
      5946  VMA_HEAVY_ASSERT(!m_pList->IsEmpty());
      +
      5947  m_pItem = m_pList->Back();
      +
      5948  }
      +
      5949  return *this;
      +
      5950  }
      +
      5951 
      +
      5952  const_iterator operator++(int)
      +
      5953  {
      +
      5954  const_iterator result = *this;
      +
      5955  ++*this;
      +
      5956  return result;
      +
      5957  }
      +
      5958  const_iterator operator--(int)
      +
      5959  {
      +
      5960  const_iterator result = *this;
      +
      5961  --*this;
      +
      5962  return result;
      +
      5963  }
      +
      5964 
      +
      5965  bool operator==(const const_iterator& rhs) const
      +
      5966  {
      +
      5967  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
      +
      5968  return m_pItem == rhs.m_pItem;
      +
      5969  }
      +
      5970  bool operator!=(const const_iterator& rhs) const
      +
      5971  {
      +
      5972  VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
      +
      5973  return m_pItem != rhs.m_pItem;
      +
      5974  }
      +
      5975 
      +
      5976  private:
      +
      5977  const_iterator(const VmaRawList<T>* pList, const VmaListItem<T>* pItem) :
      +
      5978  m_pList(pList),
      +
      5979  m_pItem(pItem)
      +
      5980  {
      +
      5981  }
      +
      5982 
      +
      5983  const VmaRawList<T>* m_pList;
      +
      5984  const VmaListItem<T>* m_pItem;
      +
      5985 
      +
      5986  friend class VmaList<T, AllocatorT>;
      +
      5987  };
      +
      5988 
      +
      5989  VmaList(const AllocatorT& allocator) : m_RawList(allocator.m_pCallbacks) { }
      +
      5990 
      +
      5991  bool empty() const { return m_RawList.IsEmpty(); }
      +
      5992  size_t size() const { return m_RawList.GetCount(); }
      +
      5993 
      +
      5994  iterator begin() { return iterator(&m_RawList, m_RawList.Front()); }
      +
      5995  iterator end() { return iterator(&m_RawList, VMA_NULL); }
      +
      5996 
      +
      5997  const_iterator cbegin() const { return const_iterator(&m_RawList, m_RawList.Front()); }
      +
      5998  const_iterator cend() const { return const_iterator(&m_RawList, VMA_NULL); }
      +
      5999 
      +
      6000  void clear() { m_RawList.Clear(); }
      +
      6001  void push_back(const T& value) { m_RawList.PushBack(value); }
      +
      6002  void erase(iterator it) { m_RawList.Remove(it.m_pItem); }
      +
      6003  iterator insert(iterator it, const T& value) { return iterator(&m_RawList, m_RawList.InsertBefore(it.m_pItem, value)); }
      +
      6004 
      +
      6005 private:
      +
      6006  VmaRawList<T> m_RawList;
      +
      6007 };
      6008 
      -
      6009 private:
      -
      6010  VmaRawList<T> m_RawList;
      -
      6011 };
      -
      6012 
      -
      6013 #endif // #if VMA_USE_STL_LIST
      -
      6014 
      -
      6016 // class VmaMap
      -
      6017 
      -
      6018 // Unused in this version.
      -
      6019 #if 0
      -
      6020 
      -
      6021 #if VMA_USE_STL_UNORDERED_MAP
      -
      6022 
      -
      6023 #define VmaPair std::pair
      -
      6024 
      -
      6025 #define VMA_MAP_TYPE(KeyT, ValueT) \
      -
      6026  std::unordered_map< KeyT, ValueT, std::hash<KeyT>, std::equal_to<KeyT>, VmaStlAllocator< std::pair<KeyT, ValueT> > >
      -
      6027 
      -
      6028 #else // #if VMA_USE_STL_UNORDERED_MAP
      -
      6029 
      -
      6030 template<typename T1, typename T2>
      -
      6031 struct VmaPair
      -
      6032 {
      -
      6033  T1 first;
      -
      6034  T2 second;
      -
      6035 
      -
      6036  VmaPair() : first(), second() { }
      -
      6037  VmaPair(const T1& firstSrc, const T2& secondSrc) : first(firstSrc), second(secondSrc) { }
      -
      6038 };
      -
      6039 
      -
      6040 /* Class compatible with subset of interface of std::unordered_map.
      -
      6041 KeyT, ValueT must be POD because they will be stored in VmaVector.
      -
      6042 */
      -
      6043 template<typename KeyT, typename ValueT>
      -
      6044 class VmaMap
      -
      6045 {
      -
      6046 public:
      -
      6047  typedef VmaPair<KeyT, ValueT> PairType;
      -
      6048  typedef PairType* iterator;
      -
      6049 
      -
      6050  VmaMap(const VmaStlAllocator<PairType>& allocator) : m_Vector(allocator) { }
      -
      6051 
      -
      6052  iterator begin() { return m_Vector.begin(); }
      -
      6053  iterator end() { return m_Vector.end(); }
      -
      6054 
      -
      6055  void insert(const PairType& pair);
      -
      6056  iterator find(const KeyT& key);
      -
      6057  void erase(iterator it);
      -
      6058 
      -
      6059 private:
      -
      6060  VmaVector< PairType, VmaStlAllocator<PairType> > m_Vector;
      -
      6061 };
      -
      6062 
      -
      6063 #define VMA_MAP_TYPE(KeyT, ValueT) VmaMap<KeyT, ValueT>
      -
      6064 
      -
      6065 template<typename FirstT, typename SecondT>
      -
      6066 struct VmaPairFirstLess
      -
      6067 {
      -
      6068  bool operator()(const VmaPair<FirstT, SecondT>& lhs, const VmaPair<FirstT, SecondT>& rhs) const
      -
      6069  {
      -
      6070  return lhs.first < rhs.first;
      -
      6071  }
      -
      6072  bool operator()(const VmaPair<FirstT, SecondT>& lhs, const FirstT& rhsFirst) const
      -
      6073  {
      -
      6074  return lhs.first < rhsFirst;
      +
      6009 #endif // #if VMA_USE_STL_LIST
      +
      6010 
      +
      6012 // class VmaIntrusiveLinkedList
      +
      6013 
      +
      6014 /*
      +
      6015 Expected interface of ItemTypeTraits:
      +
      6016 struct MyItemTypeTraits
      +
      6017 {
      +
      6018  typedef MyItem ItemType;
      +
      6019  static ItemType* GetPrev(const ItemType* item) { return item->myPrevPtr; }
      +
      6020  static ItemType* GetNext(const ItemType* item) { return item->myNextPtr; }
      +
      6021  static ItemType*& AccessPrev(ItemType* item) { return item->myPrevPtr; }
      +
      6022  static ItemType*& AccessNext(ItemType* item) { return item->myNextPtr; }
      +
      6023 };
      +
      6024 */
      +
      6025 template<typename ItemTypeTraits>
      +
      6026 class VmaIntrusiveLinkedList
      +
      6027 {
      +
      6028 public:
      +
      6029  typedef typename ItemTypeTraits::ItemType ItemType;
      +
      6030  static ItemType* GetPrev(const ItemType* item) { return ItemTypeTraits::GetPrev(item); }
      +
      6031  static ItemType* GetNext(const ItemType* item) { return ItemTypeTraits::GetNext(item); }
      +
      6032  // Movable, not copyable.
      +
      6033  VmaIntrusiveLinkedList() { }
      +
      6034  VmaIntrusiveLinkedList(const VmaIntrusiveLinkedList<ItemTypeTraits>& src) = delete;
      +
      6035  VmaIntrusiveLinkedList(VmaIntrusiveLinkedList<ItemTypeTraits>&& src) :
      +
      6036  m_Front(src.m_Front), m_Back(src.m_Back), m_Count(src.m_Count)
      +
      6037  {
      +
      6038  src.m_Front = src.m_Back = VMA_NULL;
      +
      6039  src.m_Count = 0;
      +
      6040  }
      +
      6041  ~VmaIntrusiveLinkedList()
      +
      6042  {
      +
      6043  VMA_HEAVY_ASSERT(IsEmpty());
      +
      6044  }
      +
      6045  VmaIntrusiveLinkedList<ItemTypeTraits>& operator=(const VmaIntrusiveLinkedList<ItemTypeTraits>& src) = delete;
      +
      6046  VmaIntrusiveLinkedList<ItemTypeTraits>& operator=(VmaIntrusiveLinkedList<ItemTypeTraits>&& src)
      +
      6047  {
      +
      6048  if(&src != this)
      +
      6049  {
      +
      6050  VMA_HEAVY_ASSERT(IsEmpty());
      +
      6051  m_Front = src.m_Front;
      +
      6052  m_Back = src.m_Back;
      +
      6053  m_Count = src.m_Count;
      +
      6054  src.m_Front = src.m_Back = VMA_NULL;
      +
      6055  src.m_Count = 0;
      +
      6056  }
      +
      6057  return *this;
      +
      6058  }
      +
      6059  void RemoveAll()
      +
      6060  {
      +
      6061  if(!IsEmpty())
      +
      6062  {
      +
      6063  ItemType* item = m_Back;
      +
      6064  while(item != VMA_NULL)
      +
      6065  {
      +
      6066  ItemType* const prevItem = ItemTypeTraits::AccessPrev(item);
      +
      6067  ItemTypeTraits::AccessPrev(item) = VMA_NULL;
      +
      6068  ItemTypeTraits::AccessNext(item) = VMA_NULL;
      +
      6069  item = prevItem;
      +
      6070  }
      +
      6071  m_Front = VMA_NULL;
      +
      6072  m_Back = VMA_NULL;
      +
      6073  m_Count = 0;
      +
      6074  }
      6075  }
      -
      6076 };
      -
      6077 
      -
      6078 template<typename KeyT, typename ValueT>
      -
      6079 void VmaMap<KeyT, ValueT>::insert(const PairType& pair)
      -
      6080 {
      -
      6081  const size_t indexToInsert = VmaBinaryFindFirstNotLess(
      -
      6082  m_Vector.data(),
      -
      6083  m_Vector.data() + m_Vector.size(),
      -
      6084  pair,
      -
      6085  VmaPairFirstLess<KeyT, ValueT>()) - m_Vector.data();
      -
      6086  VmaVectorInsert(m_Vector, indexToInsert, pair);
      -
      6087 }
      -
      6088 
      -
      6089 template<typename KeyT, typename ValueT>
      -
      6090 VmaPair<KeyT, ValueT>* VmaMap<KeyT, ValueT>::find(const KeyT& key)
      -
      6091 {
      -
      6092  PairType* it = VmaBinaryFindFirstNotLess(
      -
      6093  m_Vector.data(),
      -
      6094  m_Vector.data() + m_Vector.size(),
      -
      6095  key,
      -
      6096  VmaPairFirstLess<KeyT, ValueT>());
      -
      6097  if((it != m_Vector.end()) && (it->first == key))
      -
      6098  {
      -
      6099  return it;
      -
      6100  }
      -
      6101  else
      -
      6102  {
      -
      6103  return m_Vector.end();
      -
      6104  }
      -
      6105 }
      -
      6106 
      -
      6107 template<typename KeyT, typename ValueT>
      -
      6108 void VmaMap<KeyT, ValueT>::erase(iterator it)
      -
      6109 {
      -
      6110  VmaVectorRemove(m_Vector, it - m_Vector.begin());
      -
      6111 }
      -
      6112 
      -
      6113 #endif // #if VMA_USE_STL_UNORDERED_MAP
      -
      6114 
      -
      6115 #endif // #if 0
      -
      6116 
      -
      6118 
      -
      6119 class VmaDeviceMemoryBlock;
      -
      6120 
      -
      6121 enum VMA_CACHE_OPERATION { VMA_CACHE_FLUSH, VMA_CACHE_INVALIDATE };
      -
      6122 
      -
      6123 struct VmaAllocation_T
      -
      6124 {
      -
      6125 private:
      -
      6126  static const uint8_t MAP_COUNT_FLAG_PERSISTENT_MAP = 0x80;
      -
      6127 
      -
      6128  enum FLAGS
      -
      6129  {
      -
      6130  FLAG_USER_DATA_STRING = 0x01,
      -
      6131  };
      -
      6132 
      -
      6133 public:
      -
      6134  enum ALLOCATION_TYPE
      -
      6135  {
      -
      6136  ALLOCATION_TYPE_NONE,
      -
      6137  ALLOCATION_TYPE_BLOCK,
      -
      6138  ALLOCATION_TYPE_DEDICATED,
      -
      6139  };
      -
      6140 
      -
      6141  /*
      -
      6142  This struct is allocated using VmaPoolAllocator.
      -
      6143  */
      -
      6144 
      -
      6145  VmaAllocation_T(uint32_t currentFrameIndex, bool userDataString) :
      -
      6146  m_Alignment{1},
      -
      6147  m_Size{0},
      -
      6148  m_pUserData{VMA_NULL},
      -
      6149  m_LastUseFrameIndex{currentFrameIndex},
      -
      6150  m_MemoryTypeIndex{0},
      -
      6151  m_Type{(uint8_t)ALLOCATION_TYPE_NONE},
      -
      6152  m_SuballocationType{(uint8_t)VMA_SUBALLOCATION_TYPE_UNKNOWN},
      -
      6153  m_MapCount{0},
      -
      6154  m_Flags{userDataString ? (uint8_t)FLAG_USER_DATA_STRING : (uint8_t)0}
      -
      6155  {
      -
      6156 #if VMA_STATS_STRING_ENABLED
      -
      6157  m_CreationFrameIndex = currentFrameIndex;
      -
      6158  m_BufferImageUsage = 0;
      -
      6159 #endif
      -
      6160  }
      -
      6161 
      -
      6162  ~VmaAllocation_T()
      -
      6163  {
      -
      6164  VMA_ASSERT((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) == 0 && "Allocation was not unmapped before destruction.");
      -
      6165 
      -
      6166  // Check if owned string was freed.
      -
      6167  VMA_ASSERT(m_pUserData == VMA_NULL);
      -
      6168  }
      -
      6169 
      -
      6170  void InitBlockAllocation(
      -
      6171  VmaDeviceMemoryBlock* block,
      -
      6172  VkDeviceSize offset,
      -
      6173  VkDeviceSize alignment,
      -
      6174  VkDeviceSize size,
      -
      6175  uint32_t memoryTypeIndex,
      -
      6176  VmaSuballocationType suballocationType,
      -
      6177  bool mapped,
      -
      6178  bool canBecomeLost)
      -
      6179  {
      -
      6180  VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE);
      -
      6181  VMA_ASSERT(block != VMA_NULL);
      -
      6182  m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK;
      -
      6183  m_Alignment = alignment;
      -
      6184  m_Size = size;
      -
      6185  m_MemoryTypeIndex = memoryTypeIndex;
      -
      6186  m_MapCount = mapped ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0;
      -
      6187  m_SuballocationType = (uint8_t)suballocationType;
      -
      6188  m_BlockAllocation.m_Block = block;
      -
      6189  m_BlockAllocation.m_Offset = offset;
      -
      6190  m_BlockAllocation.m_CanBecomeLost = canBecomeLost;
      -
      6191  }
      -
      6192 
      -
      6193  void InitLost()
      -
      6194  {
      -
      6195  VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE);
      -
      6196  VMA_ASSERT(m_LastUseFrameIndex.load() == VMA_FRAME_INDEX_LOST);
      -
      6197  m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK;
      -
      6198  m_MemoryTypeIndex = 0;
      -
      6199  m_BlockAllocation.m_Block = VMA_NULL;
      -
      6200  m_BlockAllocation.m_Offset = 0;
      -
      6201  m_BlockAllocation.m_CanBecomeLost = true;
      -
      6202  }
      -
      6203 
      -
      6204  void ChangeBlockAllocation(
      -
      6205  VmaAllocator hAllocator,
      -
      6206  VmaDeviceMemoryBlock* block,
      -
      6207  VkDeviceSize offset);
      -
      6208 
      -
      6209  void ChangeOffset(VkDeviceSize newOffset);
      -
      6210 
      -
      6211  // pMappedData not null means allocation is created with MAPPED flag.
      -
      6212  void InitDedicatedAllocation(
      -
      6213  uint32_t memoryTypeIndex,
      -
      6214  VkDeviceMemory hMemory,
      -
      6215  VmaSuballocationType suballocationType,
      -
      6216  void* pMappedData,
      -
      6217  VkDeviceSize size)
      -
      6218  {
      -
      6219  VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE);
      -
      6220  VMA_ASSERT(hMemory != VK_NULL_HANDLE);
      -
      6221  m_Type = (uint8_t)ALLOCATION_TYPE_DEDICATED;
      -
      6222  m_Alignment = 0;
      -
      6223  m_Size = size;
      -
      6224  m_MemoryTypeIndex = memoryTypeIndex;
      -
      6225  m_SuballocationType = (uint8_t)suballocationType;
      -
      6226  m_MapCount = (pMappedData != VMA_NULL) ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0;
      -
      6227  m_DedicatedAllocation.m_hMemory = hMemory;
      -
      6228  m_DedicatedAllocation.m_pMappedData = pMappedData;
      -
      6229  }
      -
      6230 
      -
      6231  ALLOCATION_TYPE GetType() const { return (ALLOCATION_TYPE)m_Type; }
      -
      6232  VkDeviceSize GetAlignment() const { return m_Alignment; }
      -
      6233  VkDeviceSize GetSize() const { return m_Size; }
      -
      6234  bool IsUserDataString() const { return (m_Flags & FLAG_USER_DATA_STRING) != 0; }
      -
      6235  void* GetUserData() const { return m_pUserData; }
      -
      6236  void SetUserData(VmaAllocator hAllocator, void* pUserData);
      -
      6237  VmaSuballocationType GetSuballocationType() const { return (VmaSuballocationType)m_SuballocationType; }
      -
      6238 
      -
      6239  VmaDeviceMemoryBlock* GetBlock() const
      -
      6240  {
      -
      6241  VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK);
      -
      6242  return m_BlockAllocation.m_Block;
      -
      6243  }
      -
      6244  VkDeviceSize GetOffset() const;
      -
      6245  VkDeviceMemory GetMemory() const;
      -
      6246  uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; }
      -
      6247  bool IsPersistentMap() const { return (m_MapCount & MAP_COUNT_FLAG_PERSISTENT_MAP) != 0; }
      -
      6248  void* GetMappedData() const;
      -
      6249  bool CanBecomeLost() const;
      -
      6250 
      -
      6251  uint32_t GetLastUseFrameIndex() const
      -
      6252  {
      -
      6253  return m_LastUseFrameIndex.load();
      -
      6254  }
      -
      6255  bool CompareExchangeLastUseFrameIndex(uint32_t& expected, uint32_t desired)
      -
      6256  {
      -
      6257  return m_LastUseFrameIndex.compare_exchange_weak(expected, desired);
      -
      6258  }
      -
      6259  /*
      -
      6260  - If hAllocation.LastUseFrameIndex + frameInUseCount < allocator.CurrentFrameIndex,
      -
      6261  makes it lost by setting LastUseFrameIndex = VMA_FRAME_INDEX_LOST and returns true.
      -
      6262  - Else, returns false.
      -
      6263 
      -
      6264  If hAllocation is already lost, assert - you should not call it then.
      -
      6265  If hAllocation was not created with CAN_BECOME_LOST_BIT, assert.
      -
      6266  */
      -
      6267  bool MakeLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);
      -
      6268 
      -
      6269  void DedicatedAllocCalcStatsInfo(VmaStatInfo& outInfo)
      -
      6270  {
      -
      6271  VMA_ASSERT(m_Type == ALLOCATION_TYPE_DEDICATED);
      -
      6272  outInfo.blockCount = 1;
      -
      6273  outInfo.allocationCount = 1;
      -
      6274  outInfo.unusedRangeCount = 0;
      -
      6275  outInfo.usedBytes = m_Size;
      -
      6276  outInfo.unusedBytes = 0;
      -
      6277  outInfo.allocationSizeMin = outInfo.allocationSizeMax = m_Size;
      -
      6278  outInfo.unusedRangeSizeMin = UINT64_MAX;
      -
      6279  outInfo.unusedRangeSizeMax = 0;
      -
      6280  }
      -
      6281 
      -
      6282  void BlockAllocMap();
      -
      6283  void BlockAllocUnmap();
      -
      6284  VkResult DedicatedAllocMap(VmaAllocator hAllocator, void** ppData);
      -
      6285  void DedicatedAllocUnmap(VmaAllocator hAllocator);
      -
      6286 
      -
      6287 #if VMA_STATS_STRING_ENABLED
      -
      6288  uint32_t GetCreationFrameIndex() const { return m_CreationFrameIndex; }
      -
      6289  uint32_t GetBufferImageUsage() const { return m_BufferImageUsage; }
      -
      6290 
      -
      6291  void InitBufferImageUsage(uint32_t bufferImageUsage)
      -
      6292  {
      -
      6293  VMA_ASSERT(m_BufferImageUsage == 0);
      -
      6294  m_BufferImageUsage = bufferImageUsage;
      -
      6295  }
      -
      6296 
      -
      6297  void PrintParameters(class VmaJsonWriter& json) const;
      -
      6298 #endif
      -
      6299 
      -
      6300 private:
      -
      6301  VkDeviceSize m_Alignment;
      -
      6302  VkDeviceSize m_Size;
      -
      6303  void* m_pUserData;
      -
      6304  VMA_ATOMIC_UINT32 m_LastUseFrameIndex;
      -
      6305  uint32_t m_MemoryTypeIndex;
      -
      6306  uint8_t m_Type; // ALLOCATION_TYPE
      -
      6307  uint8_t m_SuballocationType; // VmaSuballocationType
      -
      6308  // Bit 0x80 is set when allocation was created with VMA_ALLOCATION_CREATE_MAPPED_BIT.
      -
      6309  // Bits with mask 0x7F are reference counter for vmaMapMemory()/vmaUnmapMemory().
      -
      6310  uint8_t m_MapCount;
      -
      6311  uint8_t m_Flags; // enum FLAGS
      -
      6312 
      -
      6313  // Allocation out of VmaDeviceMemoryBlock.
      -
      6314  struct BlockAllocation
      -
      6315  {
      -
      6316  VmaDeviceMemoryBlock* m_Block;
      -
      6317  VkDeviceSize m_Offset;
      -
      6318  bool m_CanBecomeLost;
      -
      6319  };
      -
      6320 
      -
      6321  // Allocation for an object that has its own private VkDeviceMemory.
      -
      6322  struct DedicatedAllocation
      -
      6323  {
      -
      6324  VkDeviceMemory m_hMemory;
      -
      6325  void* m_pMappedData; // Not null means memory is mapped.
      -
      6326  };
      -
      6327 
      -
      6328  union
      -
      6329  {
      -
      6330  // Allocation out of VmaDeviceMemoryBlock.
      -
      6331  BlockAllocation m_BlockAllocation;
      -
      6332  // Allocation for an object that has its own private VkDeviceMemory.
      -
      6333  DedicatedAllocation m_DedicatedAllocation;
      -
      6334  };
      -
      6335 
      -
      6336 #if VMA_STATS_STRING_ENABLED
      -
      6337  uint32_t m_CreationFrameIndex;
      -
      6338  uint32_t m_BufferImageUsage; // 0 if unknown.
      -
      6339 #endif
      -
      6340 
      -
      6341  void FreeUserDataString(VmaAllocator hAllocator);
      -
      6342 };
      -
      6343 
      -
      6344 /*
      -
      6345 Represents a region of VmaDeviceMemoryBlock that is either assigned and returned as
      -
      6346 allocated memory block or free.
      -
      6347 */
      -
      6348 struct VmaSuballocation
      -
      6349 {
      -
      6350  VkDeviceSize offset;
      -
      6351  VkDeviceSize size;
      -
      6352  VmaAllocation hAllocation;
      -
      6353  VmaSuballocationType type;
      -
      6354 };
      -
      6355 
      -
      6356 // Comparator for offsets.
      -
      6357 struct VmaSuballocationOffsetLess
      -
      6358 {
      -
      6359  bool operator()(const VmaSuballocation& lhs, const VmaSuballocation& rhs) const
      -
      6360  {
      -
      6361  return lhs.offset < rhs.offset;
      -
      6362  }
      -
      6363 };
      -
      6364 struct VmaSuballocationOffsetGreater
      -
      6365 {
      -
      6366  bool operator()(const VmaSuballocation& lhs, const VmaSuballocation& rhs) const
      -
      6367  {
      -
      6368  return lhs.offset > rhs.offset;
      -
      6369  }
      -
      6370 };
      -
      6371 
      -
      6372 typedef VmaList< VmaSuballocation, VmaStlAllocator<VmaSuballocation> > VmaSuballocationList;
      +
      6076  size_t GetCount() const { return m_Count; }
      +
      6077  bool IsEmpty() const { return m_Count == 0; }
      +
      6078  ItemType* Front() { return m_Front; }
      +
      6079  const ItemType* Front() const { return m_Front; }
      +
      6080  ItemType* Back() { return m_Back; }
      +
      6081  const ItemType* Back() const { return m_Back; }
      +
      6082  void PushBack(ItemType* item)
      +
      6083  {
      +
      6084  VMA_HEAVY_ASSERT(ItemTypeTraits::GetPrev(item) == VMA_NULL && ItemTypeTraits::GetNext(item) == VMA_NULL);
      +
      6085  if(IsEmpty())
      +
      6086  {
      +
      6087  m_Front = item;
      +
      6088  m_Back = item;
      +
      6089  m_Count = 1;
      +
      6090  }
      +
      6091  else
      +
      6092  {
      +
      6093  ItemTypeTraits::AccessPrev(item) = m_Back;
      +
      6094  ItemTypeTraits::AccessNext(m_Back) = item;
      +
      6095  m_Back = item;
      +
      6096  ++m_Count;
      +
      6097  }
      +
      6098  }
      +
      6099  void PushFront(ItemType* item)
      +
      6100  {
      +
      6101  VMA_HEAVY_ASSERT(ItemTypeTraits::GetPrev(item) == VMA_NULL && ItemTypeTraits::GetNext(item) == VMA_NULL);
      +
      6102  if(IsEmpty())
      +
      6103  {
      +
      6104  m_Front = item;
      +
      6105  m_Back = item;
      +
      6106  m_Count = 1;
      +
      6107  }
      +
      6108  else
      +
      6109  {
      +
      6110  ItemTypeTraits::AccessNext(item) = m_Front;
      +
      6111  ItemTypeTraits::AccessPrev(m_Front) = item;
      +
      6112  m_Front = item;
      +
      6113  ++m_Count;
      +
      6114  }
      +
      6115  }
      +
      6116  ItemType* PopBack()
      +
      6117  {
      +
      6118  VMA_HEAVY_ASSERT(m_Count > 0);
      +
      6119  ItemType* const backItem = m_Back;
      +
      6120  ItemType* const prevItem = ItemTypeTraits::GetPrev(backItem);
      +
      6121  if(prevItem != VMA_NULL)
      +
      6122  {
      +
      6123  ItemTypeTraits::AccessNext(prevItem) = VMA_NULL;
      +
      6124  }
      +
      6125  m_Back = prevItem;
      +
      6126  --m_Count;
      +
      6127  ItemTypeTraits::AccessPrev(backItem) = VMA_NULL;
      +
      6128  ItemTypeTraits::AccessNext(backItem) = VMA_NULL;
      +
      6129  return backItem;
      +
      6130  }
      +
      6131  ItemType* PopFront()
      +
      6132  {
      +
      6133  VMA_HEAVY_ASSERT(m_Count > 0);
      +
      6134  ItemType* const frontItem = m_Front;
      +
      6135  ItemType* const nextItem = ItemTypeTraits::GetNext(frontItem);
      +
      6136  if(nextItem != VMA_NULL)
      +
      6137  {
      +
      6138  ItemTypeTraits::AccessPrev(nextItem) = VMA_NULL;
      +
      6139  }
      +
      6140  m_Front = nextItem;
      +
      6141  --m_Count;
      +
      6142  ItemTypeTraits::AccessPrev(frontItem) = VMA_NULL;
      +
      6143  ItemTypeTraits::AccessNext(frontItem) = VMA_NULL;
      +
      6144  return frontItem;
      +
      6145  }
      +
      6146 
      +
      6147  // MyItem can be null - it means PushBack.
      +
      6148  void InsertBefore(ItemType* existingItem, ItemType* newItem)
      +
      6149  {
      +
      6150  VMA_HEAVY_ASSERT(newItem != VMA_NULL && ItemTypeTraits::GetPrev(newItem) == VMA_NULL && ItemTypeTraits::GetNext(newItem) == VMA_NULL);
      +
      6151  if(existingItem != VMA_NULL)
      +
      6152  {
      +
      6153  ItemType* const prevItem = ItemTypeTraits::GetPrev(existingItem);
      +
      6154  ItemTypeTraits::AccessPrev(newItem) = prevItem;
      +
      6155  ItemTypeTraits::AccessNext(newItem) = existingItem;
      +
      6156  ItemTypeTraits::AccessPrev(existingItem) = newItem;
      +
      6157  if(prevItem != VMA_NULL)
      +
      6158  {
      +
      6159  ItemTypeTraits::AccessNext(prevItem) = newItem;
      +
      6160  }
      +
      6161  else
      +
      6162  {
      +
      6163  VMA_HEAVY_ASSERT(m_Front == existingItem);
      +
      6164  m_Front = newItem;
      +
      6165  }
      +
      6166  ++m_Count;
      +
      6167  }
      +
      6168  else
      +
      6169  PushBack(newItem);
      +
      6170  }
      +
      6171  // MyItem can be null - it means PushFront.
      +
      6172  void InsertAfter(ItemType* existingItem, ItemType* newItem)
      +
      6173  {
      +
      6174  VMA_HEAVY_ASSERT(newItem != VMA_NULL && ItemTypeTraits::GetPrev(newItem) == VMA_NULL && ItemTypeTraits::GetNext(newItem) == VMA_NULL);
      +
      6175  if(existingItem != VMA_NULL)
      +
      6176  {
      +
      6177  ItemType* const nextItem = ItemTypeTraits::GetNext(existingItem);
      +
      6178  ItemTypeTraits::AccessNext(newItem) = nextItem;
      +
      6179  ItemTypeTraits::AccessPrev(newItem) = existingItem;
      +
      6180  ItemTypeTraits::AccessNext(existingItem) = newItem;
      +
      6181  if(nextItem != VMA_NULL)
      +
      6182  {
      +
      6183  ItemTypeTraits::AccessPrev(nextItem) = newItem;
      +
      6184  }
      +
      6185  else
      +
      6186  {
      +
      6187  VMA_HEAVY_ASSERT(m_Back == existingItem);
      +
      6188  m_Back = newItem;
      +
      6189  }
      +
      6190  ++m_Count;
      +
      6191  }
      +
      6192  else
      +
      6193  return PushFront(newItem);
      +
      6194  }
      +
      6195  void Remove(ItemType* item)
      +
      6196  {
      +
      6197  VMA_HEAVY_ASSERT(item != VMA_NULL && m_Count > 0);
      +
      6198  if(ItemTypeTraits::GetPrev(item) != VMA_NULL)
      +
      6199  {
      +
      6200  ItemTypeTraits::AccessNext(ItemTypeTraits::AccessPrev(item)) = ItemTypeTraits::GetNext(item);
      +
      6201  }
      +
      6202  else
      +
      6203  {
      +
      6204  VMA_HEAVY_ASSERT(m_Front == item);
      +
      6205  m_Front = ItemTypeTraits::GetNext(item);
      +
      6206  }
      +
      6207 
      +
      6208  if(ItemTypeTraits::GetNext(item) != VMA_NULL)
      +
      6209  {
      +
      6210  ItemTypeTraits::AccessPrev(ItemTypeTraits::AccessNext(item)) = ItemTypeTraits::GetPrev(item);
      +
      6211  }
      +
      6212  else
      +
      6213  {
      +
      6214  VMA_HEAVY_ASSERT(m_Back == item);
      +
      6215  m_Back = ItemTypeTraits::GetPrev(item);
      +
      6216  }
      +
      6217  ItemTypeTraits::AccessPrev(item) = VMA_NULL;
      +
      6218  ItemTypeTraits::AccessNext(item) = VMA_NULL;
      +
      6219  --m_Count;
      +
      6220  }
      +
      6221 private:
      +
      6222  ItemType* m_Front = VMA_NULL;
      +
      6223  ItemType* m_Back = VMA_NULL;
      +
      6224  size_t m_Count = 0;
      +
      6225 };
      +
      6226 
      +
      6228 // class VmaMap
      +
      6229 
      +
      6230 // Unused in this version.
      +
      6231 #if 0
      +
      6232 
      +
      6233 #if VMA_USE_STL_UNORDERED_MAP
      +
      6234 
      +
      6235 #define VmaPair std::pair
      +
      6236 
      +
      6237 #define VMA_MAP_TYPE(KeyT, ValueT) \
      +
      6238  std::unordered_map< KeyT, ValueT, std::hash<KeyT>, std::equal_to<KeyT>, VmaStlAllocator< std::pair<KeyT, ValueT> > >
      +
      6239 
      +
      6240 #else // #if VMA_USE_STL_UNORDERED_MAP
      +
      6241 
      +
      6242 template<typename T1, typename T2>
      +
      6243 struct VmaPair
      +
      6244 {
      +
      6245  T1 first;
      +
      6246  T2 second;
      +
      6247 
      +
      6248  VmaPair() : first(), second() { }
      +
      6249  VmaPair(const T1& firstSrc, const T2& secondSrc) : first(firstSrc), second(secondSrc) { }
      +
      6250 };
      +
      6251 
      +
      6252 /* Class compatible with subset of interface of std::unordered_map.
      +
      6253 KeyT, ValueT must be POD because they will be stored in VmaVector.
      +
      6254 */
      +
      6255 template<typename KeyT, typename ValueT>
      +
      6256 class VmaMap
      +
      6257 {
      +
      6258 public:
      +
      6259  typedef VmaPair<KeyT, ValueT> PairType;
      +
      6260  typedef PairType* iterator;
      +
      6261 
      +
      6262  VmaMap(const VmaStlAllocator<PairType>& allocator) : m_Vector(allocator) { }
      +
      6263 
      +
      6264  iterator begin() { return m_Vector.begin(); }
      +
      6265  iterator end() { return m_Vector.end(); }
      +
      6266 
      +
      6267  void insert(const PairType& pair);
      +
      6268  iterator find(const KeyT& key);
      +
      6269  void erase(iterator it);
      +
      6270 
      +
      6271 private:
      +
      6272  VmaVector< PairType, VmaStlAllocator<PairType> > m_Vector;
      +
      6273 };
      +
      6274 
      +
      6275 #define VMA_MAP_TYPE(KeyT, ValueT) VmaMap<KeyT, ValueT>
      +
      6276 
      +
      6277 template<typename FirstT, typename SecondT>
      +
      6278 struct VmaPairFirstLess
      +
      6279 {
      +
      6280  bool operator()(const VmaPair<FirstT, SecondT>& lhs, const VmaPair<FirstT, SecondT>& rhs) const
      +
      6281  {
      +
      6282  return lhs.first < rhs.first;
      +
      6283  }
      +
      6284  bool operator()(const VmaPair<FirstT, SecondT>& lhs, const FirstT& rhsFirst) const
      +
      6285  {
      +
      6286  return lhs.first < rhsFirst;
      +
      6287  }
      +
      6288 };
      +
      6289 
      +
      6290 template<typename KeyT, typename ValueT>
      +
      6291 void VmaMap<KeyT, ValueT>::insert(const PairType& pair)
      +
      6292 {
      +
      6293  const size_t indexToInsert = VmaBinaryFindFirstNotLess(
      +
      6294  m_Vector.data(),
      +
      6295  m_Vector.data() + m_Vector.size(),
      +
      6296  pair,
      +
      6297  VmaPairFirstLess<KeyT, ValueT>()) - m_Vector.data();
      +
      6298  VmaVectorInsert(m_Vector, indexToInsert, pair);
      +
      6299 }
      +
      6300 
      +
      6301 template<typename KeyT, typename ValueT>
      +
      6302 VmaPair<KeyT, ValueT>* VmaMap<KeyT, ValueT>::find(const KeyT& key)
      +
      6303 {
      +
      6304  PairType* it = VmaBinaryFindFirstNotLess(
      +
      6305  m_Vector.data(),
      +
      6306  m_Vector.data() + m_Vector.size(),
      +
      6307  key,
      +
      6308  VmaPairFirstLess<KeyT, ValueT>());
      +
      6309  if((it != m_Vector.end()) && (it->first == key))
      +
      6310  {
      +
      6311  return it;
      +
      6312  }
      +
      6313  else
      +
      6314  {
      +
      6315  return m_Vector.end();
      +
      6316  }
      +
      6317 }
      +
      6318 
      +
      6319 template<typename KeyT, typename ValueT>
      +
      6320 void VmaMap<KeyT, ValueT>::erase(iterator it)
      +
      6321 {
      +
      6322  VmaVectorRemove(m_Vector, it - m_Vector.begin());
      +
      6323 }
      +
      6324 
      +
      6325 #endif // #if VMA_USE_STL_UNORDERED_MAP
      +
      6326 
      +
      6327 #endif // #if 0
      +
      6328 
      +
      6330 
      +
      6331 class VmaDeviceMemoryBlock;
      +
      6332 
      +
      6333 enum VMA_CACHE_OPERATION { VMA_CACHE_FLUSH, VMA_CACHE_INVALIDATE };
      +
      6334 
      +
      6335 struct VmaAllocation_T
      +
      6336 {
      +
      6337 private:
      +
      6338  static const uint8_t MAP_COUNT_FLAG_PERSISTENT_MAP = 0x80;
      +
      6339 
      +
      6340  enum FLAGS
      +
      6341  {
      +
      6342  FLAG_USER_DATA_STRING = 0x01,
      +
      6343  };
      +
      6344 
      +
      6345 public:
      +
      6346  enum ALLOCATION_TYPE
      +
      6347  {
      +
      6348  ALLOCATION_TYPE_NONE,
      +
      6349  ALLOCATION_TYPE_BLOCK,
      +
      6350  ALLOCATION_TYPE_DEDICATED,
      +
      6351  };
      +
      6352 
      +
      6353  /*
      +
      6354  This struct is allocated using VmaPoolAllocator.
      +
      6355  */
      +
      6356 
      +
      6357  VmaAllocation_T(uint32_t currentFrameIndex, bool userDataString) :
      +
      6358  m_Alignment{1},
      +
      6359  m_Size{0},
      +
      6360  m_pUserData{VMA_NULL},
      +
      6361  m_LastUseFrameIndex{currentFrameIndex},
      +
      6362  m_MemoryTypeIndex{0},
      +
      6363  m_Type{(uint8_t)ALLOCATION_TYPE_NONE},
      +
      6364  m_SuballocationType{(uint8_t)VMA_SUBALLOCATION_TYPE_UNKNOWN},
      +
      6365  m_MapCount{0},
      +
      6366  m_Flags{userDataString ? (uint8_t)FLAG_USER_DATA_STRING : (uint8_t)0}
      +
      6367  {
      +
      6368 #if VMA_STATS_STRING_ENABLED
      +
      6369  m_CreationFrameIndex = currentFrameIndex;
      +
      6370  m_BufferImageUsage = 0;
      +
      6371 #endif
      +
      6372  }
      6373 
      -
      6374 // Cost of one additional allocation lost, as equivalent in bytes.
      -
      6375 static const VkDeviceSize VMA_LOST_ALLOCATION_COST = 1048576;
      -
      6376 
      -
      6377 enum class VmaAllocationRequestType
      -
      6378 {
      -
      6379  Normal,
      -
      6380  // Used by "Linear" algorithm.
      -
      6381  UpperAddress,
      -
      6382  EndOf1st,
      -
      6383  EndOf2nd,
      -
      6384 };
      -
      6385 
      -
      6386 /*
      -
      6387 Parameters of planned allocation inside a VmaDeviceMemoryBlock.
      -
      6388 
      -
      6389 If canMakeOtherLost was false:
      -
      6390 - item points to a FREE suballocation.
      -
      6391 - itemsToMakeLostCount is 0.
      -
      6392 
      -
      6393 If canMakeOtherLost was true:
      -
      6394 - item points to first of sequence of suballocations, which are either FREE,
      -
      6395  or point to VmaAllocations that can become lost.
      -
      6396 - itemsToMakeLostCount is the number of VmaAllocations that need to be made lost for
      -
      6397  the requested allocation to succeed.
      -
      6398 */
      -
      6399 struct VmaAllocationRequest
      -
      6400 {
      -
      6401  VkDeviceSize offset;
      -
      6402  VkDeviceSize sumFreeSize; // Sum size of free items that overlap with proposed allocation.
      -
      6403  VkDeviceSize sumItemSize; // Sum size of items to make lost that overlap with proposed allocation.
      -
      6404  VmaSuballocationList::iterator item;
      -
      6405  size_t itemsToMakeLostCount;
      -
      6406  void* customData;
      -
      6407  VmaAllocationRequestType type;
      -
      6408 
      -
      6409  VkDeviceSize CalcCost() const
      -
      6410  {
      -
      6411  return sumItemSize + itemsToMakeLostCount * VMA_LOST_ALLOCATION_COST;
      -
      6412  }
      -
      6413 };
      -
      6414 
      -
      6415 /*
      -
      6416 Data structure used for bookkeeping of allocations and unused ranges of memory
      -
      6417 in a single VkDeviceMemory block.
      -
      6418 */
      -
      6419 class VmaBlockMetadata
      -
      6420 {
      -
      6421 public:
      -
      6422  VmaBlockMetadata(VmaAllocator hAllocator);
      -
      6423  virtual ~VmaBlockMetadata() { }
      -
      6424  virtual void Init(VkDeviceSize size) { m_Size = size; }
      -
      6425 
      -
      6426  // Validates all data structures inside this object. If not valid, returns false.
      -
      6427  virtual bool Validate() const = 0;
      -
      6428  VkDeviceSize GetSize() const { return m_Size; }
      -
      6429  virtual size_t GetAllocationCount() const = 0;
      -
      6430  virtual VkDeviceSize GetSumFreeSize() const = 0;
      -
      6431  virtual VkDeviceSize GetUnusedRangeSizeMax() const = 0;
      -
      6432  // Returns true if this block is empty - contains only single free suballocation.
      -
      6433  virtual bool IsEmpty() const = 0;
      -
      6434 
      -
      6435  virtual void CalcAllocationStatInfo(VmaStatInfo& outInfo) const = 0;
      -
      6436  // Shouldn't modify blockCount.
      -
      6437  virtual void AddPoolStats(VmaPoolStats& inoutStats) const = 0;
      -
      6438 
      -
      6439 #if VMA_STATS_STRING_ENABLED
      -
      6440  virtual void PrintDetailedMap(class VmaJsonWriter& json) const = 0;
      -
      6441 #endif
      -
      6442 
      -
      6443  // Tries to find a place for suballocation with given parameters inside this block.
      -
      6444  // If succeeded, fills pAllocationRequest and returns true.
      -
      6445  // If failed, returns false.
      -
      6446  virtual bool CreateAllocationRequest(
      -
      6447  uint32_t currentFrameIndex,
      -
      6448  uint32_t frameInUseCount,
      -
      6449  VkDeviceSize bufferImageGranularity,
      -
      6450  VkDeviceSize allocSize,
      -
      6451  VkDeviceSize allocAlignment,
      -
      6452  bool upperAddress,
      -
      6453  VmaSuballocationType allocType,
      -
      6454  bool canMakeOtherLost,
      -
      6455  // Always one of VMA_ALLOCATION_CREATE_STRATEGY_* or VMA_ALLOCATION_INTERNAL_STRATEGY_* flags.
      -
      6456  uint32_t strategy,
      -
      6457  VmaAllocationRequest* pAllocationRequest) = 0;
      -
      6458 
      -
      6459  virtual bool MakeRequestedAllocationsLost(
      -
      6460  uint32_t currentFrameIndex,
      -
      6461  uint32_t frameInUseCount,
      -
      6462  VmaAllocationRequest* pAllocationRequest) = 0;
      -
      6463 
      -
      6464  virtual uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount) = 0;
      -
      6465 
      -
      6466  virtual VkResult CheckCorruption(const void* pBlockData) = 0;
      -
      6467 
      -
      6468  // Makes actual allocation based on request. Request must already be checked and valid.
      -
      6469  virtual void Alloc(
      -
      6470  const VmaAllocationRequest& request,
      -
      6471  VmaSuballocationType type,
      -
      6472  VkDeviceSize allocSize,
      -
      6473  VmaAllocation hAllocation) = 0;
      -
      6474 
      -
      6475  // Frees suballocation assigned to given memory region.
      -
      6476  virtual void Free(const VmaAllocation allocation) = 0;
      -
      6477  virtual void FreeAtOffset(VkDeviceSize offset) = 0;
      -
      6478 
      -
      6479 protected:
      -
      6480  const VkAllocationCallbacks* GetAllocationCallbacks() const { return m_pAllocationCallbacks; }
      -
      6481 
      -
      6482 #if VMA_STATS_STRING_ENABLED
      -
      6483  void PrintDetailedMap_Begin(class VmaJsonWriter& json,
      -
      6484  VkDeviceSize unusedBytes,
      -
      6485  size_t allocationCount,
      -
      6486  size_t unusedRangeCount) const;
      -
      6487  void PrintDetailedMap_Allocation(class VmaJsonWriter& json,
      -
      6488  VkDeviceSize offset,
      -
      6489  VmaAllocation hAllocation) const;
      -
      6490  void PrintDetailedMap_UnusedRange(class VmaJsonWriter& json,
      -
      6491  VkDeviceSize offset,
      -
      6492  VkDeviceSize size) const;
      -
      6493  void PrintDetailedMap_End(class VmaJsonWriter& json) const;
      -
      6494 #endif
      +
      6374  ~VmaAllocation_T()
      +
      6375  {
      +
      6376  VMA_ASSERT((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) == 0 && "Allocation was not unmapped before destruction.");
      +
      6377 
      +
      6378  // Check if owned string was freed.
      +
      6379  VMA_ASSERT(m_pUserData == VMA_NULL);
      +
      6380  }
      +
      6381 
      +
      6382  void InitBlockAllocation(
      +
      6383  VmaDeviceMemoryBlock* block,
      +
      6384  VkDeviceSize offset,
      +
      6385  VkDeviceSize alignment,
      +
      6386  VkDeviceSize size,
      +
      6387  uint32_t memoryTypeIndex,
      +
      6388  VmaSuballocationType suballocationType,
      +
      6389  bool mapped,
      +
      6390  bool canBecomeLost)
      +
      6391  {
      +
      6392  VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE);
      +
      6393  VMA_ASSERT(block != VMA_NULL);
      +
      6394  m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK;
      +
      6395  m_Alignment = alignment;
      +
      6396  m_Size = size;
      +
      6397  m_MemoryTypeIndex = memoryTypeIndex;
      +
      6398  m_MapCount = mapped ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0;
      +
      6399  m_SuballocationType = (uint8_t)suballocationType;
      +
      6400  m_BlockAllocation.m_Block = block;
      +
      6401  m_BlockAllocation.m_Offset = offset;
      +
      6402  m_BlockAllocation.m_CanBecomeLost = canBecomeLost;
      +
      6403  }
      +
      6404 
      +
      6405  void InitLost()
      +
      6406  {
      +
      6407  VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE);
      +
      6408  VMA_ASSERT(m_LastUseFrameIndex.load() == VMA_FRAME_INDEX_LOST);
      +
      6409  m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK;
      +
      6410  m_MemoryTypeIndex = 0;
      +
      6411  m_BlockAllocation.m_Block = VMA_NULL;
      +
      6412  m_BlockAllocation.m_Offset = 0;
      +
      6413  m_BlockAllocation.m_CanBecomeLost = true;
      +
      6414  }
      +
      6415 
      +
      6416  void ChangeBlockAllocation(
      +
      6417  VmaAllocator hAllocator,
      +
      6418  VmaDeviceMemoryBlock* block,
      +
      6419  VkDeviceSize offset);
      +
      6420 
      +
      6421  void ChangeOffset(VkDeviceSize newOffset);
      +
      6422 
      +
      6423  // pMappedData not null means allocation is created with MAPPED flag.
      +
      6424  void InitDedicatedAllocation(
      +
      6425  uint32_t memoryTypeIndex,
      +
      6426  VkDeviceMemory hMemory,
      +
      6427  VmaSuballocationType suballocationType,
      +
      6428  void* pMappedData,
      +
      6429  VkDeviceSize size)
      +
      6430  {
      +
      6431  VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE);
      +
      6432  VMA_ASSERT(hMemory != VK_NULL_HANDLE);
      +
      6433  m_Type = (uint8_t)ALLOCATION_TYPE_DEDICATED;
      +
      6434  m_Alignment = 0;
      +
      6435  m_Size = size;
      +
      6436  m_MemoryTypeIndex = memoryTypeIndex;
      +
      6437  m_SuballocationType = (uint8_t)suballocationType;
      +
      6438  m_MapCount = (pMappedData != VMA_NULL) ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0;
      +
      6439  m_DedicatedAllocation.m_hMemory = hMemory;
      +
      6440  m_DedicatedAllocation.m_pMappedData = pMappedData;
      +
      6441  m_DedicatedAllocation.m_Prev = VMA_NULL;
      +
      6442  m_DedicatedAllocation.m_Next = VMA_NULL;
      +
      6443  }
      +
      6444 
      +
      6445  ALLOCATION_TYPE GetType() const { return (ALLOCATION_TYPE)m_Type; }
      +
      6446  VkDeviceSize GetAlignment() const { return m_Alignment; }
      +
      6447  VkDeviceSize GetSize() const { return m_Size; }
      +
      6448  bool IsUserDataString() const { return (m_Flags & FLAG_USER_DATA_STRING) != 0; }
      +
      6449  void* GetUserData() const { return m_pUserData; }
      +
      6450  void SetUserData(VmaAllocator hAllocator, void* pUserData);
      +
      6451  VmaSuballocationType GetSuballocationType() const { return (VmaSuballocationType)m_SuballocationType; }
      +
      6452 
      +
      6453  VmaDeviceMemoryBlock* GetBlock() const
      +
      6454  {
      +
      6455  VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK);
      +
      6456  return m_BlockAllocation.m_Block;
      +
      6457  }
      +
      6458  VkDeviceSize GetOffset() const;
      +
      6459  VkDeviceMemory GetMemory() const;
      +
      6460  uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; }
      +
      6461  bool IsPersistentMap() const { return (m_MapCount & MAP_COUNT_FLAG_PERSISTENT_MAP) != 0; }
      +
      6462  void* GetMappedData() const;
      +
      6463  bool CanBecomeLost() const;
      +
      6464 
      +
      6465  uint32_t GetLastUseFrameIndex() const
      +
      6466  {
      +
      6467  return m_LastUseFrameIndex.load();
      +
      6468  }
      +
      6469  bool CompareExchangeLastUseFrameIndex(uint32_t& expected, uint32_t desired)
      +
      6470  {
      +
      6471  return m_LastUseFrameIndex.compare_exchange_weak(expected, desired);
      +
      6472  }
      +
      6473  /*
      +
      6474  - If hAllocation.LastUseFrameIndex + frameInUseCount < allocator.CurrentFrameIndex,
      +
      6475  makes it lost by setting LastUseFrameIndex = VMA_FRAME_INDEX_LOST and returns true.
      +
      6476  - Else, returns false.
      +
      6477 
      +
      6478  If hAllocation is already lost, assert - you should not call it then.
      +
      6479  If hAllocation was not created with CAN_BECOME_LOST_BIT, assert.
      +
      6480  */
      +
      6481  bool MakeLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);
      +
      6482 
      +
      6483  void DedicatedAllocCalcStatsInfo(VmaStatInfo& outInfo)
      +
      6484  {
      +
      6485  VMA_ASSERT(m_Type == ALLOCATION_TYPE_DEDICATED);
      +
      6486  outInfo.blockCount = 1;
      +
      6487  outInfo.allocationCount = 1;
      +
      6488  outInfo.unusedRangeCount = 0;
      +
      6489  outInfo.usedBytes = m_Size;
      +
      6490  outInfo.unusedBytes = 0;
      +
      6491  outInfo.allocationSizeMin = outInfo.allocationSizeMax = m_Size;
      +
      6492  outInfo.unusedRangeSizeMin = UINT64_MAX;
      +
      6493  outInfo.unusedRangeSizeMax = 0;
      +
      6494  }
      6495 
      -
      6496 private:
      -
      6497  VkDeviceSize m_Size;
      -
      6498  const VkAllocationCallbacks* m_pAllocationCallbacks;
      -
      6499 };
      +
      6496  void BlockAllocMap();
      +
      6497  void BlockAllocUnmap();
      +
      6498  VkResult DedicatedAllocMap(VmaAllocator hAllocator, void** ppData);
      +
      6499  void DedicatedAllocUnmap(VmaAllocator hAllocator);
      6500 
      -
      6501 #define VMA_VALIDATE(cond) do { if(!(cond)) { \
      -
      6502  VMA_ASSERT(0 && "Validation failed: " #cond); \
      -
      6503  return false; \
      -
      6504  } } while(false)
      -
      6505 
      -
      6506 class VmaBlockMetadata_Generic : public VmaBlockMetadata
      -
      6507 {
      -
      6508  VMA_CLASS_NO_COPY(VmaBlockMetadata_Generic)
      -
      6509 public:
      -
      6510  VmaBlockMetadata_Generic(VmaAllocator hAllocator);
      -
      6511  virtual ~VmaBlockMetadata_Generic();
      -
      6512  virtual void Init(VkDeviceSize size);
      +
      6501 #if VMA_STATS_STRING_ENABLED
      +
      6502  uint32_t GetCreationFrameIndex() const { return m_CreationFrameIndex; }
      +
      6503  uint32_t GetBufferImageUsage() const { return m_BufferImageUsage; }
      +
      6504 
      +
      6505  void InitBufferImageUsage(uint32_t bufferImageUsage)
      +
      6506  {
      +
      6507  VMA_ASSERT(m_BufferImageUsage == 0);
      +
      6508  m_BufferImageUsage = bufferImageUsage;
      +
      6509  }
      +
      6510 
      +
      6511  void PrintParameters(class VmaJsonWriter& json) const;
      +
      6512 #endif
      6513 
      -
      6514  virtual bool Validate() const;
      -
      6515  virtual size_t GetAllocationCount() const { return m_Suballocations.size() - m_FreeCount; }
      -
      6516  virtual VkDeviceSize GetSumFreeSize() const { return m_SumFreeSize; }
      -
      6517  virtual VkDeviceSize GetUnusedRangeSizeMax() const;
      -
      6518  virtual bool IsEmpty() const;
      -
      6519 
      -
      6520  virtual void CalcAllocationStatInfo(VmaStatInfo& outInfo) const;
      -
      6521  virtual void AddPoolStats(VmaPoolStats& inoutStats) const;
      -
      6522 
      -
      6523 #if VMA_STATS_STRING_ENABLED
      -
      6524  virtual void PrintDetailedMap(class VmaJsonWriter& json) const;
      -
      6525 #endif
      +
      6514 private:
      +
      6515  VkDeviceSize m_Alignment;
      +
      6516  VkDeviceSize m_Size;
      +
      6517  void* m_pUserData;
      +
      6518  VMA_ATOMIC_UINT32 m_LastUseFrameIndex;
      +
      6519  uint32_t m_MemoryTypeIndex;
      +
      6520  uint8_t m_Type; // ALLOCATION_TYPE
      +
      6521  uint8_t m_SuballocationType; // VmaSuballocationType
      +
      6522  // Bit 0x80 is set when allocation was created with VMA_ALLOCATION_CREATE_MAPPED_BIT.
      +
      6523  // Bits with mask 0x7F are reference counter for vmaMapMemory()/vmaUnmapMemory().
      +
      6524  uint8_t m_MapCount;
      +
      6525  uint8_t m_Flags; // enum FLAGS
      6526 
      -
      6527  virtual bool CreateAllocationRequest(
      -
      6528  uint32_t currentFrameIndex,
      -
      6529  uint32_t frameInUseCount,
      -
      6530  VkDeviceSize bufferImageGranularity,
      -
      6531  VkDeviceSize allocSize,
      -
      6532  VkDeviceSize allocAlignment,
      -
      6533  bool upperAddress,
      -
      6534  VmaSuballocationType allocType,
      -
      6535  bool canMakeOtherLost,
      -
      6536  uint32_t strategy,
      -
      6537  VmaAllocationRequest* pAllocationRequest);
      -
      6538 
      -
      6539  virtual bool MakeRequestedAllocationsLost(
      -
      6540  uint32_t currentFrameIndex,
      -
      6541  uint32_t frameInUseCount,
      -
      6542  VmaAllocationRequest* pAllocationRequest);
      +
      6527  // Allocation out of VmaDeviceMemoryBlock.
      +
      6528  struct BlockAllocation
      +
      6529  {
      +
      6530  VmaDeviceMemoryBlock* m_Block;
      +
      6531  VkDeviceSize m_Offset;
      +
      6532  bool m_CanBecomeLost;
      +
      6533  };
      +
      6534 
      +
      6535  // Allocation for an object that has its own private VkDeviceMemory.
      +
      6536  struct DedicatedAllocation
      +
      6537  {
      +
      6538  VkDeviceMemory m_hMemory;
      +
      6539  void* m_pMappedData; // Not null means memory is mapped.
      +
      6540  VmaAllocation_T* m_Prev;
      +
      6541  VmaAllocation_T* m_Next;
      +
      6542  };
      6543 
      -
      6544  virtual uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);
      -
      6545 
      -
      6546  virtual VkResult CheckCorruption(const void* pBlockData);
      -
      6547 
      -
      6548  virtual void Alloc(
      -
      6549  const VmaAllocationRequest& request,
      -
      6550  VmaSuballocationType type,
      -
      6551  VkDeviceSize allocSize,
      -
      6552  VmaAllocation hAllocation);
      -
      6553 
      -
      6554  virtual void Free(const VmaAllocation allocation);
      -
      6555  virtual void FreeAtOffset(VkDeviceSize offset);
      +
      6544  union
      +
      6545  {
      +
      6546  // Allocation out of VmaDeviceMemoryBlock.
      +
      6547  BlockAllocation m_BlockAllocation;
      +
      6548  // Allocation for an object that has its own private VkDeviceMemory.
      +
      6549  DedicatedAllocation m_DedicatedAllocation;
      +
      6550  };
      +
      6551 
      +
      6552 #if VMA_STATS_STRING_ENABLED
      +
      6553  uint32_t m_CreationFrameIndex;
      +
      6554  uint32_t m_BufferImageUsage; // 0 if unknown.
      +
      6555 #endif
      6556 
      -
      6558  // For defragmentation
      -
      6559 
      -
      6560  bool IsBufferImageGranularityConflictPossible(
      -
      6561  VkDeviceSize bufferImageGranularity,
      -
      6562  VmaSuballocationType& inOutPrevSuballocType) const;
      -
      6563 
      -
      6564 private:
      -
      6565  friend class VmaDefragmentationAlgorithm_Generic;
      -
      6566  friend class VmaDefragmentationAlgorithm_Fast;
      -
      6567 
      -
      6568  uint32_t m_FreeCount;
      -
      6569  VkDeviceSize m_SumFreeSize;
      -
      6570  VmaSuballocationList m_Suballocations;
      -
      6571  // Suballocations that are free and have size greater than certain threshold.
      -
      6572  // Sorted by size, ascending.
      -
      6573  VmaVector< VmaSuballocationList::iterator, VmaStlAllocator< VmaSuballocationList::iterator > > m_FreeSuballocationsBySize;
      -
      6574 
      -
      6575  bool ValidateFreeSuballocationList() const;
      -
      6576 
      -
      6577  // Checks if requested suballocation with given parameters can be placed in given pFreeSuballocItem.
      -
      6578  // If yes, fills pOffset and returns true. If no, returns false.
      -
      6579  bool CheckAllocation(
      -
      6580  uint32_t currentFrameIndex,
      -
      6581  uint32_t frameInUseCount,
      -
      6582  VkDeviceSize bufferImageGranularity,
      -
      6583  VkDeviceSize allocSize,
      -
      6584  VkDeviceSize allocAlignment,
      -
      6585  VmaSuballocationType allocType,
      -
      6586  VmaSuballocationList::const_iterator suballocItem,
      -
      6587  bool canMakeOtherLost,
      -
      6588  VkDeviceSize* pOffset,
      -
      6589  size_t* itemsToMakeLostCount,
      -
      6590  VkDeviceSize* pSumFreeSize,
      -
      6591  VkDeviceSize* pSumItemSize) const;
      -
      6592  // Given free suballocation, it merges it with following one, which must also be free.
      -
      6593  void MergeFreeWithNext(VmaSuballocationList::iterator item);
      -
      6594  // Releases given suballocation, making it free.
      -
      6595  // Merges it with adjacent free suballocations if applicable.
      -
      6596  // Returns iterator to new free suballocation at this place.
      -
      6597  VmaSuballocationList::iterator FreeSuballocation(VmaSuballocationList::iterator suballocItem);
      -
      6598  // Given free suballocation, it inserts it into sorted list of
      -
      6599  // m_FreeSuballocationsBySize if it's suitable.
      -
      6600  void RegisterFreeSuballocation(VmaSuballocationList::iterator item);
      -
      6601  // Given free suballocation, it removes it from sorted list of
      -
      6602  // m_FreeSuballocationsBySize if it's suitable.
      -
      6603  void UnregisterFreeSuballocation(VmaSuballocationList::iterator item);
      -
      6604 };
      -
      6605 
      -
      6606 /*
      -
      6607 Allocations and their references in internal data structure look like this:
      -
      6608 
      -
      6609 if(m_2ndVectorMode == SECOND_VECTOR_EMPTY):
      -
      6610 
      -
      6611  0 +-------+
      -
      6612  | |
      -
      6613  | |
      -
      6614  | |
      -
      6615  +-------+
      -
      6616  | Alloc | 1st[m_1stNullItemsBeginCount]
      -
      6617  +-------+
      -
      6618  | Alloc | 1st[m_1stNullItemsBeginCount + 1]
      -
      6619  +-------+
      -
      6620  | ... |
      -
      6621  +-------+
      -
      6622  | Alloc | 1st[1st.size() - 1]
      -
      6623  +-------+
      -
      6624  | |
      -
      6625  | |
      -
      6626  | |
      -
      6627 GetSize() +-------+
      -
      6628 
      -
      6629 if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER):
      +
      6557  void FreeUserDataString(VmaAllocator hAllocator);
      +
      6558 
      +
      6559  friend struct VmaDedicatedAllocationListItemTraits;
      +
      6560 };
      +
      6561 
      +
      6562 struct VmaDedicatedAllocationListItemTraits
      +
      6563 {
      +
      6564  typedef VmaAllocation_T ItemType;
      +
      6565  static ItemType* GetPrev(const ItemType* item)
      +
      6566  {
      +
      6567  VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
      +
      6568  return item->m_DedicatedAllocation.m_Prev;
      +
      6569  }
      +
      6570  static ItemType* GetNext(const ItemType* item)
      +
      6571  {
      +
      6572  VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
      +
      6573  return item->m_DedicatedAllocation.m_Next;
      +
      6574  }
      +
      6575  static ItemType*& AccessPrev(ItemType* item)
      +
      6576  {
      +
      6577  VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
      +
      6578  return item->m_DedicatedAllocation.m_Prev;
      +
      6579  }
      +
      6580  static ItemType*& AccessNext(ItemType* item){
      +
      6581  VMA_HEAVY_ASSERT(item->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
      +
      6582  return item->m_DedicatedAllocation.m_Next;
      +
      6583  }
      +
      6584 };
      +
      6585 
      +
      6586 /*
      +
      6587 Represents a region of VmaDeviceMemoryBlock that is either assigned and returned as
      +
      6588 allocated memory block or free.
      +
      6589 */
      +
      6590 struct VmaSuballocation
      +
      6591 {
      +
      6592  VkDeviceSize offset;
      +
      6593  VkDeviceSize size;
      +
      6594  VmaAllocation hAllocation;
      +
      6595  VmaSuballocationType type;
      +
      6596 };
      +
      6597 
      +
      6598 // Comparator for offsets.
      +
      6599 struct VmaSuballocationOffsetLess
      +
      6600 {
      +
      6601  bool operator()(const VmaSuballocation& lhs, const VmaSuballocation& rhs) const
      +
      6602  {
      +
      6603  return lhs.offset < rhs.offset;
      +
      6604  }
      +
      6605 };
      +
      6606 struct VmaSuballocationOffsetGreater
      +
      6607 {
      +
      6608  bool operator()(const VmaSuballocation& lhs, const VmaSuballocation& rhs) const
      +
      6609  {
      +
      6610  return lhs.offset > rhs.offset;
      +
      6611  }
      +
      6612 };
      +
      6613 
      +
      6614 typedef VmaList< VmaSuballocation, VmaStlAllocator<VmaSuballocation> > VmaSuballocationList;
      +
      6615 
      +
      6616 // Cost of one additional allocation lost, as equivalent in bytes.
      +
      6617 static const VkDeviceSize VMA_LOST_ALLOCATION_COST = 1048576;
      +
      6618 
      +
      6619 enum class VmaAllocationRequestType
      +
      6620 {
      +
      6621  Normal,
      +
      6622  // Used by "Linear" algorithm.
      +
      6623  UpperAddress,
      +
      6624  EndOf1st,
      +
      6625  EndOf2nd,
      +
      6626 };
      +
      6627 
      +
      6628 /*
      +
      6629 Parameters of planned allocation inside a VmaDeviceMemoryBlock.
      6630 
      -
      6631  0 +-------+
      -
      6632  | Alloc | 2nd[0]
      -
      6633  +-------+
      -
      6634  | Alloc | 2nd[1]
      -
      6635  +-------+
      -
      6636  | ... |
      -
      6637  +-------+
      -
      6638  | Alloc | 2nd[2nd.size() - 1]
      -
      6639  +-------+
      -
      6640  | |
      -
      6641  | |
      -
      6642  | |
      -
      6643  +-------+
      -
      6644  | Alloc | 1st[m_1stNullItemsBeginCount]
      -
      6645  +-------+
      -
      6646  | Alloc | 1st[m_1stNullItemsBeginCount + 1]
      -
      6647  +-------+
      -
      6648  | ... |
      -
      6649  +-------+
      -
      6650  | Alloc | 1st[1st.size() - 1]
      -
      6651  +-------+
      -
      6652  | |
      -
      6653 GetSize() +-------+
      -
      6654 
      -
      6655 if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK):
      -
      6656 
      -
      6657  0 +-------+
      -
      6658  | |
      -
      6659  | |
      -
      6660  | |
      -
      6661  +-------+
      -
      6662  | Alloc | 1st[m_1stNullItemsBeginCount]
      -
      6663  +-------+
      -
      6664  | Alloc | 1st[m_1stNullItemsBeginCount + 1]
      -
      6665  +-------+
      -
      6666  | ... |
      -
      6667  +-------+
      -
      6668  | Alloc | 1st[1st.size() - 1]
      -
      6669  +-------+
      -
      6670  | |
      -
      6671  | |
      -
      6672  | |
      -
      6673  +-------+
      -
      6674  | Alloc | 2nd[2nd.size() - 1]
      -
      6675  +-------+
      -
      6676  | ... |
      -
      6677  +-------+
      -
      6678  | Alloc | 2nd[1]
      -
      6679  +-------+
      -
      6680  | Alloc | 2nd[0]
      -
      6681 GetSize() +-------+
      -
      6682 
      -
      6683 */
      -
      6684 class VmaBlockMetadata_Linear : public VmaBlockMetadata
      -
      6685 {
      -
      6686  VMA_CLASS_NO_COPY(VmaBlockMetadata_Linear)
      -
      6687 public:
      -
      6688  VmaBlockMetadata_Linear(VmaAllocator hAllocator);
      -
      6689  virtual ~VmaBlockMetadata_Linear();
      -
      6690  virtual void Init(VkDeviceSize size);
      -
      6691 
      -
      6692  virtual bool Validate() const;
      -
      6693  virtual size_t GetAllocationCount() const;
      -
      6694  virtual VkDeviceSize GetSumFreeSize() const { return m_SumFreeSize; }
      -
      6695  virtual VkDeviceSize GetUnusedRangeSizeMax() const;
      -
      6696  virtual bool IsEmpty() const { return GetAllocationCount() == 0; }
      -
      6697 
      -
      6698  virtual void CalcAllocationStatInfo(VmaStatInfo& outInfo) const;
      -
      6699  virtual void AddPoolStats(VmaPoolStats& inoutStats) const;
      +
      6631 If canMakeOtherLost was false:
      +
      6632 - item points to a FREE suballocation.
      +
      6633 - itemsToMakeLostCount is 0.
      +
      6634 
      +
      6635 If canMakeOtherLost was true:
      +
      6636 - item points to first of sequence of suballocations, which are either FREE,
      +
      6637  or point to VmaAllocations that can become lost.
      +
      6638 - itemsToMakeLostCount is the number of VmaAllocations that need to be made lost for
      +
      6639  the requested allocation to succeed.
      +
      6640 */
      +
      6641 struct VmaAllocationRequest
      +
      6642 {
      +
      6643  VkDeviceSize offset;
      +
      6644  VkDeviceSize sumFreeSize; // Sum size of free items that overlap with proposed allocation.
      +
      6645  VkDeviceSize sumItemSize; // Sum size of items to make lost that overlap with proposed allocation.
      +
      6646  VmaSuballocationList::iterator item;
      +
      6647  size_t itemsToMakeLostCount;
      +
      6648  void* customData;
      +
      6649  VmaAllocationRequestType type;
      +
      6650 
      +
      6651  VkDeviceSize CalcCost() const
      +
      6652  {
      +
      6653  return sumItemSize + itemsToMakeLostCount * VMA_LOST_ALLOCATION_COST;
      +
      6654  }
      +
      6655 };
      +
      6656 
      +
      6657 /*
      +
      6658 Data structure used for bookkeeping of allocations and unused ranges of memory
      +
      6659 in a single VkDeviceMemory block.
      +
      6660 */
      +
      6661 class VmaBlockMetadata
      +
      6662 {
      +
      6663 public:
      +
      6664  VmaBlockMetadata(VmaAllocator hAllocator);
      +
      6665  virtual ~VmaBlockMetadata() { }
      +
      6666  virtual void Init(VkDeviceSize size) { m_Size = size; }
      +
      6667 
      +
      6668  // Validates all data structures inside this object. If not valid, returns false.
      +
      6669  virtual bool Validate() const = 0;
      +
      6670  VkDeviceSize GetSize() const { return m_Size; }
      +
      6671  virtual size_t GetAllocationCount() const = 0;
      +
      6672  virtual VkDeviceSize GetSumFreeSize() const = 0;
      +
      6673  virtual VkDeviceSize GetUnusedRangeSizeMax() const = 0;
      +
      6674  // Returns true if this block is empty - contains only single free suballocation.
      +
      6675  virtual bool IsEmpty() const = 0;
      +
      6676 
      +
      6677  virtual void CalcAllocationStatInfo(VmaStatInfo& outInfo) const = 0;
      +
      6678  // Shouldn't modify blockCount.
      +
      6679  virtual void AddPoolStats(VmaPoolStats& inoutStats) const = 0;
      +
      6680 
      +
      6681 #if VMA_STATS_STRING_ENABLED
      +
      6682  virtual void PrintDetailedMap(class VmaJsonWriter& json) const = 0;
      +
      6683 #endif
      +
      6684 
      +
      6685  // Tries to find a place for suballocation with given parameters inside this block.
      +
      6686  // If succeeded, fills pAllocationRequest and returns true.
      +
      6687  // If failed, returns false.
      +
      6688  virtual bool CreateAllocationRequest(
      +
      6689  uint32_t currentFrameIndex,
      +
      6690  uint32_t frameInUseCount,
      +
      6691  VkDeviceSize bufferImageGranularity,
      +
      6692  VkDeviceSize allocSize,
      +
      6693  VkDeviceSize allocAlignment,
      +
      6694  bool upperAddress,
      +
      6695  VmaSuballocationType allocType,
      +
      6696  bool canMakeOtherLost,
      +
      6697  // Always one of VMA_ALLOCATION_CREATE_STRATEGY_* or VMA_ALLOCATION_INTERNAL_STRATEGY_* flags.
      +
      6698  uint32_t strategy,
      +
      6699  VmaAllocationRequest* pAllocationRequest) = 0;
      6700 
      -
      6701 #if VMA_STATS_STRING_ENABLED
      -
      6702  virtual void PrintDetailedMap(class VmaJsonWriter& json) const;
      -
      6703 #endif
      -
      6704 
      -
      6705  virtual bool CreateAllocationRequest(
      -
      6706  uint32_t currentFrameIndex,
      -
      6707  uint32_t frameInUseCount,
      -
      6708  VkDeviceSize bufferImageGranularity,
      -
      6709  VkDeviceSize allocSize,
      -
      6710  VkDeviceSize allocAlignment,
      -
      6711  bool upperAddress,
      -
      6712  VmaSuballocationType allocType,
      -
      6713  bool canMakeOtherLost,
      -
      6714  uint32_t strategy,
      -
      6715  VmaAllocationRequest* pAllocationRequest);
      +
      6701  virtual bool MakeRequestedAllocationsLost(
      +
      6702  uint32_t currentFrameIndex,
      +
      6703  uint32_t frameInUseCount,
      +
      6704  VmaAllocationRequest* pAllocationRequest) = 0;
      +
      6705 
      +
      6706  virtual uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount) = 0;
      +
      6707 
      +
      6708  virtual VkResult CheckCorruption(const void* pBlockData) = 0;
      +
      6709 
      +
      6710  // Makes actual allocation based on request. Request must already be checked and valid.
      +
      6711  virtual void Alloc(
      +
      6712  const VmaAllocationRequest& request,
      +
      6713  VmaSuballocationType type,
      +
      6714  VkDeviceSize allocSize,
      +
      6715  VmaAllocation hAllocation) = 0;
      6716 
      -
      6717  virtual bool MakeRequestedAllocationsLost(
      -
      6718  uint32_t currentFrameIndex,
      -
      6719  uint32_t frameInUseCount,
      -
      6720  VmaAllocationRequest* pAllocationRequest);
      -
      6721 
      -
      6722  virtual uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);
      +
      6717  // Frees suballocation assigned to given memory region.
      +
      6718  virtual void Free(const VmaAllocation allocation) = 0;
      +
      6719  virtual void FreeAtOffset(VkDeviceSize offset) = 0;
      +
      6720 
      +
      6721 protected:
      +
      6722  const VkAllocationCallbacks* GetAllocationCallbacks() const { return m_pAllocationCallbacks; }
      6723 
      -
      6724  virtual VkResult CheckCorruption(const void* pBlockData);
      -
      6725 
      -
      6726  virtual void Alloc(
      -
      6727  const VmaAllocationRequest& request,
      -
      6728  VmaSuballocationType type,
      -
      6729  VkDeviceSize allocSize,
      -
      6730  VmaAllocation hAllocation);
      -
      6731 
      -
      6732  virtual void Free(const VmaAllocation allocation);
      -
      6733  virtual void FreeAtOffset(VkDeviceSize offset);
      -
      6734 
      -
      6735 private:
      -
      6736  /*
      -
      6737  There are two suballocation vectors, used in ping-pong way.
      -
      6738  The one with index m_1stVectorIndex is called 1st.
      -
      6739  The one with index (m_1stVectorIndex ^ 1) is called 2nd.
      -
      6740  2nd can be non-empty only when 1st is not empty.
      -
      6741  When 2nd is not empty, m_2ndVectorMode indicates its mode of operation.
      -
      6742  */
      -
      6743  typedef VmaVector< VmaSuballocation, VmaStlAllocator<VmaSuballocation> > SuballocationVectorType;
      -
      6744 
      -
      6745  enum SECOND_VECTOR_MODE
      -
      6746  {
      -
      6747  SECOND_VECTOR_EMPTY,
      -
      6748  /*
      -
      6749  Suballocations in 2nd vector are created later than the ones in 1st, but they
      -
      6750  all have smaller offset.
      -
      6751  */
      -
      6752  SECOND_VECTOR_RING_BUFFER,
      -
      6753  /*
      -
      6754  Suballocations in 2nd vector are upper side of double stack.
      -
      6755  They all have offsets higher than those in 1st vector.
      -
      6756  Top of this stack means smaller offsets, but higher indices in this vector.
      -
      6757  */
      -
      6758  SECOND_VECTOR_DOUBLE_STACK,
      -
      6759  };
      -
      6760 
      -
      6761  VkDeviceSize m_SumFreeSize;
      -
      6762  SuballocationVectorType m_Suballocations0, m_Suballocations1;
      -
      6763  uint32_t m_1stVectorIndex;
      -
      6764  SECOND_VECTOR_MODE m_2ndVectorMode;
      -
      6765 
      -
      6766  SuballocationVectorType& AccessSuballocations1st() { return m_1stVectorIndex ? m_Suballocations1 : m_Suballocations0; }
      -
      6767  SuballocationVectorType& AccessSuballocations2nd() { return m_1stVectorIndex ? m_Suballocations0 : m_Suballocations1; }
      -
      6768  const SuballocationVectorType& AccessSuballocations1st() const { return m_1stVectorIndex ? m_Suballocations1 : m_Suballocations0; }
      -
      6769  const SuballocationVectorType& AccessSuballocations2nd() const { return m_1stVectorIndex ? m_Suballocations0 : m_Suballocations1; }
      -
      6770 
      -
      6771  // Number of items in 1st vector with hAllocation = null at the beginning.
      -
      6772  size_t m_1stNullItemsBeginCount;
      -
      6773  // Number of other items in 1st vector with hAllocation = null somewhere in the middle.
      -
      6774  size_t m_1stNullItemsMiddleCount;
      -
      6775  // Number of items in 2nd vector with hAllocation = null.
      -
      6776  size_t m_2ndNullItemsCount;
      -
      6777 
      -
      6778  bool ShouldCompact1st() const;
      -
      6779  void CleanupAfterFree();
      +
      6724 #if VMA_STATS_STRING_ENABLED
      +
      6725  void PrintDetailedMap_Begin(class VmaJsonWriter& json,
      +
      6726  VkDeviceSize unusedBytes,
      +
      6727  size_t allocationCount,
      +
      6728  size_t unusedRangeCount) const;
      +
      6729  void PrintDetailedMap_Allocation(class VmaJsonWriter& json,
      +
      6730  VkDeviceSize offset,
      +
      6731  VmaAllocation hAllocation) const;
      +
      6732  void PrintDetailedMap_UnusedRange(class VmaJsonWriter& json,
      +
      6733  VkDeviceSize offset,
      +
      6734  VkDeviceSize size) const;
      +
      6735  void PrintDetailedMap_End(class VmaJsonWriter& json) const;
      +
      6736 #endif
      +
      6737 
      +
      6738 private:
      +
      6739  VkDeviceSize m_Size;
      +
      6740  const VkAllocationCallbacks* m_pAllocationCallbacks;
      +
      6741 };
      +
      6742 
      +
      6743 #define VMA_VALIDATE(cond) do { if(!(cond)) { \
      +
      6744  VMA_ASSERT(0 && "Validation failed: " #cond); \
      +
      6745  return false; \
      +
      6746  } } while(false)
      +
      6747 
      +
      6748 class VmaBlockMetadata_Generic : public VmaBlockMetadata
      +
      6749 {
      +
      6750  VMA_CLASS_NO_COPY(VmaBlockMetadata_Generic)
      +
      6751 public:
      +
      6752  VmaBlockMetadata_Generic(VmaAllocator hAllocator);
      +
      6753  virtual ~VmaBlockMetadata_Generic();
      +
      6754  virtual void Init(VkDeviceSize size);
      +
      6755 
      +
      6756  virtual bool Validate() const;
      +
      6757  virtual size_t GetAllocationCount() const { return m_Suballocations.size() - m_FreeCount; }
      +
      6758  virtual VkDeviceSize GetSumFreeSize() const { return m_SumFreeSize; }
      +
      6759  virtual VkDeviceSize GetUnusedRangeSizeMax() const;
      +
      6760  virtual bool IsEmpty() const;
      +
      6761 
      +
      6762  virtual void CalcAllocationStatInfo(VmaStatInfo& outInfo) const;
      +
      6763  virtual void AddPoolStats(VmaPoolStats& inoutStats) const;
      +
      6764 
      +
      6765 #if VMA_STATS_STRING_ENABLED
      +
      6766  virtual void PrintDetailedMap(class VmaJsonWriter& json) const;
      +
      6767 #endif
      +
      6768 
      +
      6769  virtual bool CreateAllocationRequest(
      +
      6770  uint32_t currentFrameIndex,
      +
      6771  uint32_t frameInUseCount,
      +
      6772  VkDeviceSize bufferImageGranularity,
      +
      6773  VkDeviceSize allocSize,
      +
      6774  VkDeviceSize allocAlignment,
      +
      6775  bool upperAddress,
      +
      6776  VmaSuballocationType allocType,
      +
      6777  bool canMakeOtherLost,
      +
      6778  uint32_t strategy,
      +
      6779  VmaAllocationRequest* pAllocationRequest);
      6780 
      -
      6781  bool CreateAllocationRequest_LowerAddress(
      +
      6781  virtual bool MakeRequestedAllocationsLost(
      6782  uint32_t currentFrameIndex,
      6783  uint32_t frameInUseCount,
      -
      6784  VkDeviceSize bufferImageGranularity,
      -
      6785  VkDeviceSize allocSize,
      -
      6786  VkDeviceSize allocAlignment,
      -
      6787  VmaSuballocationType allocType,
      -
      6788  bool canMakeOtherLost,
      -
      6789  uint32_t strategy,
      -
      6790  VmaAllocationRequest* pAllocationRequest);
      -
      6791  bool CreateAllocationRequest_UpperAddress(
      -
      6792  uint32_t currentFrameIndex,
      -
      6793  uint32_t frameInUseCount,
      -
      6794  VkDeviceSize bufferImageGranularity,
      -
      6795  VkDeviceSize allocSize,
      -
      6796  VkDeviceSize allocAlignment,
      -
      6797  VmaSuballocationType allocType,
      -
      6798  bool canMakeOtherLost,
      -
      6799  uint32_t strategy,
      -
      6800  VmaAllocationRequest* pAllocationRequest);
      -
      6801 };
      -
      6802 
      -
      6803 /*
      -
      6804 - GetSize() is the original size of allocated memory block.
      -
      6805 - m_UsableSize is this size aligned down to a power of two.
      -
      6806  All allocations and calculations happen relative to m_UsableSize.
      -
      6807 - GetUnusableSize() is the difference between them.
      -
      6808  It is repoted as separate, unused range, not available for allocations.
      -
      6809 
      -
      6810 Node at level 0 has size = m_UsableSize.
      -
      6811 Each next level contains nodes with size 2 times smaller than current level.
      -
      6812 m_LevelCount is the maximum number of levels to use in the current object.
      -
      6813 */
      -
      6814 class VmaBlockMetadata_Buddy : public VmaBlockMetadata
      -
      6815 {
      -
      6816  VMA_CLASS_NO_COPY(VmaBlockMetadata_Buddy)
      -
      6817 public:
      -
      6818  VmaBlockMetadata_Buddy(VmaAllocator hAllocator);
      -
      6819  virtual ~VmaBlockMetadata_Buddy();
      -
      6820  virtual void Init(VkDeviceSize size);
      -
      6821 
      -
      6822  virtual bool Validate() const;
      -
      6823  virtual size_t GetAllocationCount() const { return m_AllocationCount; }
      -
      6824  virtual VkDeviceSize GetSumFreeSize() const { return m_SumFreeSize + GetUnusableSize(); }
      -
      6825  virtual VkDeviceSize GetUnusedRangeSizeMax() const;
      -
      6826  virtual bool IsEmpty() const { return m_Root->type == Node::TYPE_FREE; }
      -
      6827 
      -
      6828  virtual void CalcAllocationStatInfo(VmaStatInfo& outInfo) const;
      -
      6829  virtual void AddPoolStats(VmaPoolStats& inoutStats) const;
      -
      6830 
      -
      6831 #if VMA_STATS_STRING_ENABLED
      -
      6832  virtual void PrintDetailedMap(class VmaJsonWriter& json) const;
      -
      6833 #endif
      -
      6834 
      -
      6835  virtual bool CreateAllocationRequest(
      -
      6836  uint32_t currentFrameIndex,
      -
      6837  uint32_t frameInUseCount,
      -
      6838  VkDeviceSize bufferImageGranularity,
      -
      6839  VkDeviceSize allocSize,
      -
      6840  VkDeviceSize allocAlignment,
      -
      6841  bool upperAddress,
      -
      6842  VmaSuballocationType allocType,
      -
      6843  bool canMakeOtherLost,
      -
      6844  uint32_t strategy,
      -
      6845  VmaAllocationRequest* pAllocationRequest);
      -
      6846 
      -
      6847  virtual bool MakeRequestedAllocationsLost(
      -
      6848  uint32_t currentFrameIndex,
      -
      6849  uint32_t frameInUseCount,
      -
      6850  VmaAllocationRequest* pAllocationRequest);
      -
      6851 
      -
      6852  virtual uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);
      -
      6853 
      -
      6854  virtual VkResult CheckCorruption(const void* pBlockData) { return VK_ERROR_FEATURE_NOT_PRESENT; }
      -
      6855 
      -
      6856  virtual void Alloc(
      -
      6857  const VmaAllocationRequest& request,
      -
      6858  VmaSuballocationType type,
      -
      6859  VkDeviceSize allocSize,
      -
      6860  VmaAllocation hAllocation);
      -
      6861 
      -
      6862  virtual void Free(const VmaAllocation allocation) { FreeAtOffset(allocation, allocation->GetOffset()); }
      -
      6863  virtual void FreeAtOffset(VkDeviceSize offset) { FreeAtOffset(VMA_NULL, offset); }
      -
      6864 
      -
      6865 private:
      -
      6866  static const VkDeviceSize MIN_NODE_SIZE = 32;
      -
      6867  static const size_t MAX_LEVELS = 30;
      -
      6868 
      -
      6869  struct ValidationContext
      -
      6870  {
      -
      6871  size_t calculatedAllocationCount;
      -
      6872  size_t calculatedFreeCount;
      -
      6873  VkDeviceSize calculatedSumFreeSize;
      -
      6874 
      -
      6875  ValidationContext() :
      -
      6876  calculatedAllocationCount(0),
      -
      6877  calculatedFreeCount(0),
      -
      6878  calculatedSumFreeSize(0) { }
      -
      6879  };
      -
      6880 
      -
      6881  struct Node
      -
      6882  {
      -
      6883  VkDeviceSize offset;
      -
      6884  enum TYPE
      -
      6885  {
      -
      6886  TYPE_FREE,
      -
      6887  TYPE_ALLOCATION,
      -
      6888  TYPE_SPLIT,
      -
      6889  TYPE_COUNT
      -
      6890  } type;
      -
      6891  Node* parent;
      -
      6892  Node* buddy;
      -
      6893 
      -
      6894  union
      -
      6895  {
      -
      6896  struct
      -
      6897  {
      -
      6898  Node* prev;
      -
      6899  Node* next;
      -
      6900  } free;
      -
      6901  struct
      -
      6902  {
      -
      6903  VmaAllocation alloc;
      -
      6904  } allocation;
      -
      6905  struct
      -
      6906  {
      -
      6907  Node* leftChild;
      -
      6908  } split;
      -
      6909  };
      -
      6910  };
      -
      6911 
      -
      6912  // Size of the memory block aligned down to a power of two.
      -
      6913  VkDeviceSize m_UsableSize;
      -
      6914  uint32_t m_LevelCount;
      -
      6915 
      -
      6916  Node* m_Root;
      -
      6917  struct {
      -
      6918  Node* front;
      -
      6919  Node* back;
      -
      6920  } m_FreeList[MAX_LEVELS];
      -
      6921  // Number of nodes in the tree with type == TYPE_ALLOCATION.
      -
      6922  size_t m_AllocationCount;
      -
      6923  // Number of nodes in the tree with type == TYPE_FREE.
      -
      6924  size_t m_FreeCount;
      -
      6925  // This includes space wasted due to internal fragmentation. Doesn't include unusable size.
      -
      6926  VkDeviceSize m_SumFreeSize;
      -
      6927 
      -
      6928  VkDeviceSize GetUnusableSize() const { return GetSize() - m_UsableSize; }
      -
      6929  void DeleteNode(Node* node);
      -
      6930  bool ValidateNode(ValidationContext& ctx, const Node* parent, const Node* curr, uint32_t level, VkDeviceSize levelNodeSize) const;
      -
      6931  uint32_t AllocSizeToLevel(VkDeviceSize allocSize) const;
      -
      6932  inline VkDeviceSize LevelToNodeSize(uint32_t level) const { return m_UsableSize >> level; }
      -
      6933  // Alloc passed just for validation. Can be null.
      -
      6934  void FreeAtOffset(VmaAllocation alloc, VkDeviceSize offset);
      -
      6935  void CalcAllocationStatInfoNode(VmaStatInfo& outInfo, const Node* node, VkDeviceSize levelNodeSize) const;
      -
      6936  // Adds node to the front of FreeList at given level.
      -
      6937  // node->type must be FREE.
      -
      6938  // node->free.prev, next can be undefined.
      -
      6939  void AddToFreeListFront(uint32_t level, Node* node);
      -
      6940  // Removes node from FreeList at given level.
      -
      6941  // node->type must be FREE.
      -
      6942  // node->free.prev, next stay untouched.
      -
      6943  void RemoveFromFreeList(uint32_t level, Node* node);
      -
      6944 
      -
      6945 #if VMA_STATS_STRING_ENABLED
      -
      6946  void PrintDetailedMapNode(class VmaJsonWriter& json, const Node* node, VkDeviceSize levelNodeSize) const;
      -
      6947 #endif
      -
      6948 };
      -
      6949 
      -
      6950 /*
      -
      6951 Represents a single block of device memory (`VkDeviceMemory`) with all the
      -
      6952 data about its regions (aka suballocations, #VmaAllocation), assigned and free.
      -
      6953 
      -
      6954 Thread-safety: This class must be externally synchronized.
      -
      6955 */
      -
      6956 class VmaDeviceMemoryBlock
      -
      6957 {
      -
      6958  VMA_CLASS_NO_COPY(VmaDeviceMemoryBlock)
      -
      6959 public:
      -
      6960  VmaBlockMetadata* m_pMetadata;
      -
      6961 
      -
      6962  VmaDeviceMemoryBlock(VmaAllocator hAllocator);
      +
      6784  VmaAllocationRequest* pAllocationRequest);
      +
      6785 
      +
      6786  virtual uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);
      +
      6787 
      +
      6788  virtual VkResult CheckCorruption(const void* pBlockData);
      +
      6789 
      +
      6790  virtual void Alloc(
      +
      6791  const VmaAllocationRequest& request,
      +
      6792  VmaSuballocationType type,
      +
      6793  VkDeviceSize allocSize,
      +
      6794  VmaAllocation hAllocation);
      +
      6795 
      +
      6796  virtual void Free(const VmaAllocation allocation);
      +
      6797  virtual void FreeAtOffset(VkDeviceSize offset);
      +
      6798 
      +
      6800  // For defragmentation
      +
      6801 
      +
      6802  bool IsBufferImageGranularityConflictPossible(
      +
      6803  VkDeviceSize bufferImageGranularity,
      +
      6804  VmaSuballocationType& inOutPrevSuballocType) const;
      +
      6805 
      +
      6806 private:
      +
      6807  friend class VmaDefragmentationAlgorithm_Generic;
      +
      6808  friend class VmaDefragmentationAlgorithm_Fast;
      +
      6809 
      +
      6810  uint32_t m_FreeCount;
      +
      6811  VkDeviceSize m_SumFreeSize;
      +
      6812  VmaSuballocationList m_Suballocations;
      +
      6813  // Suballocations that are free and have size greater than certain threshold.
      +
      6814  // Sorted by size, ascending.
      +
      6815  VmaVector< VmaSuballocationList::iterator, VmaStlAllocator< VmaSuballocationList::iterator > > m_FreeSuballocationsBySize;
      +
      6816 
      +
      6817  bool ValidateFreeSuballocationList() const;
      +
      6818 
      +
      6819  // Checks if requested suballocation with given parameters can be placed in given pFreeSuballocItem.
      +
      6820  // If yes, fills pOffset and returns true. If no, returns false.
      +
      6821  bool CheckAllocation(
      +
      6822  uint32_t currentFrameIndex,
      +
      6823  uint32_t frameInUseCount,
      +
      6824  VkDeviceSize bufferImageGranularity,
      +
      6825  VkDeviceSize allocSize,
      +
      6826  VkDeviceSize allocAlignment,
      +
      6827  VmaSuballocationType allocType,
      +
      6828  VmaSuballocationList::const_iterator suballocItem,
      +
      6829  bool canMakeOtherLost,
      +
      6830  VkDeviceSize* pOffset,
      +
      6831  size_t* itemsToMakeLostCount,
      +
      6832  VkDeviceSize* pSumFreeSize,
      +
      6833  VkDeviceSize* pSumItemSize) const;
      +
      6834  // Given free suballocation, it merges it with following one, which must also be free.
      +
      6835  void MergeFreeWithNext(VmaSuballocationList::iterator item);
      +
      6836  // Releases given suballocation, making it free.
      +
      6837  // Merges it with adjacent free suballocations if applicable.
      +
      6838  // Returns iterator to new free suballocation at this place.
      +
      6839  VmaSuballocationList::iterator FreeSuballocation(VmaSuballocationList::iterator suballocItem);
      +
      6840  // Given free suballocation, it inserts it into sorted list of
      +
      6841  // m_FreeSuballocationsBySize if it's suitable.
      +
      6842  void RegisterFreeSuballocation(VmaSuballocationList::iterator item);
      +
      6843  // Given free suballocation, it removes it from sorted list of
      +
      6844  // m_FreeSuballocationsBySize if it's suitable.
      +
      6845  void UnregisterFreeSuballocation(VmaSuballocationList::iterator item);
      +
      6846 };
      +
      6847 
      +
      6848 /*
      +
      6849 Allocations and their references in internal data structure look like this:
      +
      6850 
      +
      6851 if(m_2ndVectorMode == SECOND_VECTOR_EMPTY):
      +
      6852 
      +
      6853  0 +-------+
      +
      6854  | |
      +
      6855  | |
      +
      6856  | |
      +
      6857  +-------+
      +
      6858  | Alloc | 1st[m_1stNullItemsBeginCount]
      +
      6859  +-------+
      +
      6860  | Alloc | 1st[m_1stNullItemsBeginCount + 1]
      +
      6861  +-------+
      +
      6862  | ... |
      +
      6863  +-------+
      +
      6864  | Alloc | 1st[1st.size() - 1]
      +
      6865  +-------+
      +
      6866  | |
      +
      6867  | |
      +
      6868  | |
      +
      6869 GetSize() +-------+
      +
      6870 
      +
      6871 if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER):
      +
      6872 
      +
      6873  0 +-------+
      +
      6874  | Alloc | 2nd[0]
      +
      6875  +-------+
      +
      6876  | Alloc | 2nd[1]
      +
      6877  +-------+
      +
      6878  | ... |
      +
      6879  +-------+
      +
      6880  | Alloc | 2nd[2nd.size() - 1]
      +
      6881  +-------+
      +
      6882  | |
      +
      6883  | |
      +
      6884  | |
      +
      6885  +-------+
      +
      6886  | Alloc | 1st[m_1stNullItemsBeginCount]
      +
      6887  +-------+
      +
      6888  | Alloc | 1st[m_1stNullItemsBeginCount + 1]
      +
      6889  +-------+
      +
      6890  | ... |
      +
      6891  +-------+
      +
      6892  | Alloc | 1st[1st.size() - 1]
      +
      6893  +-------+
      +
      6894  | |
      +
      6895 GetSize() +-------+
      +
      6896 
      +
      6897 if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK):
      +
      6898 
      +
      6899  0 +-------+
      +
      6900  | |
      +
      6901  | |
      +
      6902  | |
      +
      6903  +-------+
      +
      6904  | Alloc | 1st[m_1stNullItemsBeginCount]
      +
      6905  +-------+
      +
      6906  | Alloc | 1st[m_1stNullItemsBeginCount + 1]
      +
      6907  +-------+
      +
      6908  | ... |
      +
      6909  +-------+
      +
      6910  | Alloc | 1st[1st.size() - 1]
      +
      6911  +-------+
      +
      6912  | |
      +
      6913  | |
      +
      6914  | |
      +
      6915  +-------+
      +
      6916  | Alloc | 2nd[2nd.size() - 1]
      +
      6917  +-------+
      +
      6918  | ... |
      +
      6919  +-------+
      +
      6920  | Alloc | 2nd[1]
      +
      6921  +-------+
      +
      6922  | Alloc | 2nd[0]
      +
      6923 GetSize() +-------+
      +
      6924 
      +
      6925 */
      +
      6926 class VmaBlockMetadata_Linear : public VmaBlockMetadata
      +
      6927 {
      +
      6928  VMA_CLASS_NO_COPY(VmaBlockMetadata_Linear)
      +
      6929 public:
      +
      6930  VmaBlockMetadata_Linear(VmaAllocator hAllocator);
      +
      6931  virtual ~VmaBlockMetadata_Linear();
      +
      6932  virtual void Init(VkDeviceSize size);
      +
      6933 
      +
      6934  virtual bool Validate() const;
      +
      6935  virtual size_t GetAllocationCount() const;
      +
      6936  virtual VkDeviceSize GetSumFreeSize() const { return m_SumFreeSize; }
      +
      6937  virtual VkDeviceSize GetUnusedRangeSizeMax() const;
      +
      6938  virtual bool IsEmpty() const { return GetAllocationCount() == 0; }
      +
      6939 
      +
      6940  virtual void CalcAllocationStatInfo(VmaStatInfo& outInfo) const;
      +
      6941  virtual void AddPoolStats(VmaPoolStats& inoutStats) const;
      +
      6942 
      +
      6943 #if VMA_STATS_STRING_ENABLED
      +
      6944  virtual void PrintDetailedMap(class VmaJsonWriter& json) const;
      +
      6945 #endif
      +
      6946 
      +
      6947  virtual bool CreateAllocationRequest(
      +
      6948  uint32_t currentFrameIndex,
      +
      6949  uint32_t frameInUseCount,
      +
      6950  VkDeviceSize bufferImageGranularity,
      +
      6951  VkDeviceSize allocSize,
      +
      6952  VkDeviceSize allocAlignment,
      +
      6953  bool upperAddress,
      +
      6954  VmaSuballocationType allocType,
      +
      6955  bool canMakeOtherLost,
      +
      6956  uint32_t strategy,
      +
      6957  VmaAllocationRequest* pAllocationRequest);
      +
      6958 
      +
      6959  virtual bool MakeRequestedAllocationsLost(
      +
      6960  uint32_t currentFrameIndex,
      +
      6961  uint32_t frameInUseCount,
      +
      6962  VmaAllocationRequest* pAllocationRequest);
      6963 
      -
      6964  ~VmaDeviceMemoryBlock()
      -
      6965  {
      -
      6966  VMA_ASSERT(m_MapCount == 0 && "VkDeviceMemory block is being destroyed while it is still mapped.");
      -
      6967  VMA_ASSERT(m_hMemory == VK_NULL_HANDLE);
      -
      6968  }
      -
      6969 
      -
      6970  // Always call after construction.
      -
      6971  void Init(
      -
      6972  VmaAllocator hAllocator,
      -
      6973  VmaPool hParentPool,
      -
      6974  uint32_t newMemoryTypeIndex,
      -
      6975  VkDeviceMemory newMemory,
      -
      6976  VkDeviceSize newSize,
      -
      6977  uint32_t id,
      -
      6978  uint32_t algorithm);
      -
      6979  // Always call before destruction.
      -
      6980  void Destroy(VmaAllocator allocator);
      -
      6981 
      -
      6982  VmaPool GetParentPool() const { return m_hParentPool; }
      -
      6983  VkDeviceMemory GetDeviceMemory() const { return m_hMemory; }
      -
      6984  uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; }
      -
      6985  uint32_t GetId() const { return m_Id; }
      -
      6986  void* GetMappedData() const { return m_pMappedData; }
      -
      6987 
      -
      6988  // Validates all data structures inside this object. If not valid, returns false.
      -
      6989  bool Validate() const;
      -
      6990 
      -
      6991  VkResult CheckCorruption(VmaAllocator hAllocator);
      -
      6992 
      -
      6993  // ppData can be null.
      -
      6994  VkResult Map(VmaAllocator hAllocator, uint32_t count, void** ppData);
      -
      6995  void Unmap(VmaAllocator hAllocator, uint32_t count);
      -
      6996 
      -
      6997  VkResult WriteMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize);
      -
      6998  VkResult ValidateMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize);
      -
      6999 
      -
      7000  VkResult BindBufferMemory(
      -
      7001  const VmaAllocator hAllocator,
      -
      7002  const VmaAllocation hAllocation,
      -
      7003  VkDeviceSize allocationLocalOffset,
      -
      7004  VkBuffer hBuffer,
      -
      7005  const void* pNext);
      -
      7006  VkResult BindImageMemory(
      -
      7007  const VmaAllocator hAllocator,
      -
      7008  const VmaAllocation hAllocation,
      -
      7009  VkDeviceSize allocationLocalOffset,
      -
      7010  VkImage hImage,
      -
      7011  const void* pNext);
      +
      6964  virtual uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);
      +
      6965 
      +
      6966  virtual VkResult CheckCorruption(const void* pBlockData);
      +
      6967 
      +
      6968  virtual void Alloc(
      +
      6969  const VmaAllocationRequest& request,
      +
      6970  VmaSuballocationType type,
      +
      6971  VkDeviceSize allocSize,
      +
      6972  VmaAllocation hAllocation);
      +
      6973 
      +
      6974  virtual void Free(const VmaAllocation allocation);
      +
      6975  virtual void FreeAtOffset(VkDeviceSize offset);
      +
      6976 
      +
      6977 private:
      +
      6978  /*
      +
      6979  There are two suballocation vectors, used in ping-pong way.
      +
      6980  The one with index m_1stVectorIndex is called 1st.
      +
      6981  The one with index (m_1stVectorIndex ^ 1) is called 2nd.
      +
      6982  2nd can be non-empty only when 1st is not empty.
      +
      6983  When 2nd is not empty, m_2ndVectorMode indicates its mode of operation.
      +
      6984  */
      +
      6985  typedef VmaVector< VmaSuballocation, VmaStlAllocator<VmaSuballocation> > SuballocationVectorType;
      +
      6986 
      +
      6987  enum SECOND_VECTOR_MODE
      +
      6988  {
      +
      6989  SECOND_VECTOR_EMPTY,
      +
      6990  /*
      +
      6991  Suballocations in 2nd vector are created later than the ones in 1st, but they
      +
      6992  all have smaller offset.
      +
      6993  */
      +
      6994  SECOND_VECTOR_RING_BUFFER,
      +
      6995  /*
      +
      6996  Suballocations in 2nd vector are upper side of double stack.
      +
      6997  They all have offsets higher than those in 1st vector.
      +
      6998  Top of this stack means smaller offsets, but higher indices in this vector.
      +
      6999  */
      +
      7000  SECOND_VECTOR_DOUBLE_STACK,
      +
      7001  };
      +
      7002 
      +
      7003  VkDeviceSize m_SumFreeSize;
      +
      7004  SuballocationVectorType m_Suballocations0, m_Suballocations1;
      +
      7005  uint32_t m_1stVectorIndex;
      +
      7006  SECOND_VECTOR_MODE m_2ndVectorMode;
      +
      7007 
      +
      7008  SuballocationVectorType& AccessSuballocations1st() { return m_1stVectorIndex ? m_Suballocations1 : m_Suballocations0; }
      +
      7009  SuballocationVectorType& AccessSuballocations2nd() { return m_1stVectorIndex ? m_Suballocations0 : m_Suballocations1; }
      +
      7010  const SuballocationVectorType& AccessSuballocations1st() const { return m_1stVectorIndex ? m_Suballocations1 : m_Suballocations0; }
      +
      7011  const SuballocationVectorType& AccessSuballocations2nd() const { return m_1stVectorIndex ? m_Suballocations0 : m_Suballocations1; }
      7012 
      -
      7013 private:
      -
      7014  VmaPool m_hParentPool; // VK_NULL_HANDLE if not belongs to custom pool.
      -
      7015  uint32_t m_MemoryTypeIndex;
      -
      7016  uint32_t m_Id;
      -
      7017  VkDeviceMemory m_hMemory;
      -
      7018 
      -
      7019  /*
      -
      7020  Protects access to m_hMemory so it's not used by multiple threads simultaneously, e.g. vkMapMemory, vkBindBufferMemory.
      -
      7021  Also protects m_MapCount, m_pMappedData.
      -
      7022  Allocations, deallocations, any change in m_pMetadata is protected by parent's VmaBlockVector::m_Mutex.
      -
      7023  */
      -
      7024  VMA_MUTEX m_Mutex;
      -
      7025  uint32_t m_MapCount;
      -
      7026  void* m_pMappedData;
      -
      7027 };
      -
      7028 
      -
      7029 struct VmaPointerLess
      -
      7030 {
      -
      7031  bool operator()(const void* lhs, const void* rhs) const
      -
      7032  {
      -
      7033  return lhs < rhs;
      -
      7034  }
      -
      7035 };
      -
      7036 
      -
      7037 struct VmaDefragmentationMove
      -
      7038 {
      -
      7039  size_t srcBlockIndex;
      -
      7040  size_t dstBlockIndex;
      -
      7041  VkDeviceSize srcOffset;
      -
      7042  VkDeviceSize dstOffset;
      -
      7043  VkDeviceSize size;
      -
      7044  VmaAllocation hAllocation;
      -
      7045  VmaDeviceMemoryBlock* pSrcBlock;
      -
      7046  VmaDeviceMemoryBlock* pDstBlock;
      -
      7047 };
      -
      7048 
      -
      7049 class VmaDefragmentationAlgorithm;
      -
      7050 
      -
      7051 /*
      -
      7052 Sequence of VmaDeviceMemoryBlock. Represents memory blocks allocated for a specific
      -
      7053 Vulkan memory type.
      -
      7054 
      -
      7055 Synchronized internally with a mutex.
      -
      7056 */
      -
      7057 struct VmaBlockVector
      -
      7058 {
      -
      7059  VMA_CLASS_NO_COPY(VmaBlockVector)
      -
      7060 public:
      -
      7061  VmaBlockVector(
      -
      7062  VmaAllocator hAllocator,
      -
      7063  VmaPool hParentPool,
      -
      7064  uint32_t memoryTypeIndex,
      -
      7065  VkDeviceSize preferredBlockSize,
      -
      7066  size_t minBlockCount,
      -
      7067  size_t maxBlockCount,
      -
      7068  VkDeviceSize bufferImageGranularity,
      -
      7069  uint32_t frameInUseCount,
      -
      7070  bool explicitBlockSize,
      -
      7071  uint32_t algorithm,
      -
      7072  float priority);
      -
      7073  ~VmaBlockVector();
      -
      7074 
      -
      7075  VkResult CreateMinBlocks();
      +
      7013  // Number of items in 1st vector with hAllocation = null at the beginning.
      +
      7014  size_t m_1stNullItemsBeginCount;
      +
      7015  // Number of other items in 1st vector with hAllocation = null somewhere in the middle.
      +
      7016  size_t m_1stNullItemsMiddleCount;
      +
      7017  // Number of items in 2nd vector with hAllocation = null.
      +
      7018  size_t m_2ndNullItemsCount;
      +
      7019 
      +
      7020  bool ShouldCompact1st() const;
      +
      7021  void CleanupAfterFree();
      +
      7022 
      +
      7023  bool CreateAllocationRequest_LowerAddress(
      +
      7024  uint32_t currentFrameIndex,
      +
      7025  uint32_t frameInUseCount,
      +
      7026  VkDeviceSize bufferImageGranularity,
      +
      7027  VkDeviceSize allocSize,
      +
      7028  VkDeviceSize allocAlignment,
      +
      7029  VmaSuballocationType allocType,
      +
      7030  bool canMakeOtherLost,
      +
      7031  uint32_t strategy,
      +
      7032  VmaAllocationRequest* pAllocationRequest);
      +
      7033  bool CreateAllocationRequest_UpperAddress(
      +
      7034  uint32_t currentFrameIndex,
      +
      7035  uint32_t frameInUseCount,
      +
      7036  VkDeviceSize bufferImageGranularity,
      +
      7037  VkDeviceSize allocSize,
      +
      7038  VkDeviceSize allocAlignment,
      +
      7039  VmaSuballocationType allocType,
      +
      7040  bool canMakeOtherLost,
      +
      7041  uint32_t strategy,
      +
      7042  VmaAllocationRequest* pAllocationRequest);
      +
      7043 };
      +
      7044 
      +
      7045 /*
      +
      7046 - GetSize() is the original size of allocated memory block.
      +
      7047 - m_UsableSize is this size aligned down to a power of two.
      +
      7048  All allocations and calculations happen relative to m_UsableSize.
      +
      7049 - GetUnusableSize() is the difference between them.
      +
      7050  It is repoted as separate, unused range, not available for allocations.
      +
      7051 
      +
      7052 Node at level 0 has size = m_UsableSize.
      +
      7053 Each next level contains nodes with size 2 times smaller than current level.
      +
      7054 m_LevelCount is the maximum number of levels to use in the current object.
      +
      7055 */
      +
      7056 class VmaBlockMetadata_Buddy : public VmaBlockMetadata
      +
      7057 {
      +
      7058  VMA_CLASS_NO_COPY(VmaBlockMetadata_Buddy)
      +
      7059 public:
      +
      7060  VmaBlockMetadata_Buddy(VmaAllocator hAllocator);
      +
      7061  virtual ~VmaBlockMetadata_Buddy();
      +
      7062  virtual void Init(VkDeviceSize size);
      +
      7063 
      +
      7064  virtual bool Validate() const;
      +
      7065  virtual size_t GetAllocationCount() const { return m_AllocationCount; }
      +
      7066  virtual VkDeviceSize GetSumFreeSize() const { return m_SumFreeSize + GetUnusableSize(); }
      +
      7067  virtual VkDeviceSize GetUnusedRangeSizeMax() const;
      +
      7068  virtual bool IsEmpty() const { return m_Root->type == Node::TYPE_FREE; }
      +
      7069 
      +
      7070  virtual void CalcAllocationStatInfo(VmaStatInfo& outInfo) const;
      +
      7071  virtual void AddPoolStats(VmaPoolStats& inoutStats) const;
      +
      7072 
      +
      7073 #if VMA_STATS_STRING_ENABLED
      +
      7074  virtual void PrintDetailedMap(class VmaJsonWriter& json) const;
      +
      7075 #endif
      7076 
      -
      7077  VmaAllocator GetAllocator() const { return m_hAllocator; }
      -
      7078  VmaPool GetParentPool() const { return m_hParentPool; }
      -
      7079  bool IsCustomPool() const { return m_hParentPool != VMA_NULL; }
      -
      7080  uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; }
      -
      7081  VkDeviceSize GetPreferredBlockSize() const { return m_PreferredBlockSize; }
      -
      7082  VkDeviceSize GetBufferImageGranularity() const { return m_BufferImageGranularity; }
      -
      7083  uint32_t GetFrameInUseCount() const { return m_FrameInUseCount; }
      -
      7084  uint32_t GetAlgorithm() const { return m_Algorithm; }
      -
      7085 
      -
      7086  void GetPoolStats(VmaPoolStats* pStats);
      -
      7087 
      -
      7088  bool IsEmpty();
      -
      7089  bool IsCorruptionDetectionEnabled() const;
      -
      7090 
      -
      7091  VkResult Allocate(
      -
      7092  uint32_t currentFrameIndex,
      -
      7093  VkDeviceSize size,
      -
      7094  VkDeviceSize alignment,
      -
      7095  const VmaAllocationCreateInfo& createInfo,
      -
      7096  VmaSuballocationType suballocType,
      -
      7097  size_t allocationCount,
      -
      7098  VmaAllocation* pAllocations);
      -
      7099 
      -
      7100  void Free(const VmaAllocation hAllocation);
      -
      7101 
      -
      7102  // Adds statistics of this BlockVector to pStats.
      -
      7103  void AddStats(VmaStats* pStats);
      -
      7104 
      -
      7105 #if VMA_STATS_STRING_ENABLED
      -
      7106  void PrintDetailedMap(class VmaJsonWriter& json);
      -
      7107 #endif
      -
      7108 
      -
      7109  void MakePoolAllocationsLost(
      -
      7110  uint32_t currentFrameIndex,
      -
      7111  size_t* pLostAllocationCount);
      -
      7112  VkResult CheckCorruption();
      -
      7113 
      -
      7114  // Saves results in pCtx->res.
      -
      7115  void Defragment(
      -
      7116  class VmaBlockVectorDefragmentationContext* pCtx,
      - -
      7118  VkDeviceSize& maxCpuBytesToMove, uint32_t& maxCpuAllocationsToMove,
      -
      7119  VkDeviceSize& maxGpuBytesToMove, uint32_t& maxGpuAllocationsToMove,
      -
      7120  VkCommandBuffer commandBuffer);
      -
      7121  void DefragmentationEnd(
      -
      7122  class VmaBlockVectorDefragmentationContext* pCtx,
      -
      7123  uint32_t flags,
      -
      7124  VmaDefragmentationStats* pStats);
      -
      7125 
      -
      7126  uint32_t ProcessDefragmentations(
      -
      7127  class VmaBlockVectorDefragmentationContext *pCtx,
      -
      7128  VmaDefragmentationPassMoveInfo* pMove, uint32_t maxMoves);
      -
      7129 
      -
      7130  void CommitDefragmentations(
      -
      7131  class VmaBlockVectorDefragmentationContext *pCtx,
      -
      7132  VmaDefragmentationStats* pStats);
      -
      7133 
      -
      7135  // To be used only while the m_Mutex is locked. Used during defragmentation.
      -
      7136 
      -
      7137  size_t GetBlockCount() const { return m_Blocks.size(); }
      -
      7138  VmaDeviceMemoryBlock* GetBlock(size_t index) const { return m_Blocks[index]; }
      -
      7139  size_t CalcAllocationCount() const;
      -
      7140  bool IsBufferImageGranularityConflictPossible() const;
      -
      7141 
      -
      7142 private:
      -
      7143  friend class VmaDefragmentationAlgorithm_Generic;
      -
      7144 
      -
      7145  const VmaAllocator m_hAllocator;
      -
      7146  const VmaPool m_hParentPool;
      -
      7147  const uint32_t m_MemoryTypeIndex;
      -
      7148  const VkDeviceSize m_PreferredBlockSize;
      -
      7149  const size_t m_MinBlockCount;
      -
      7150  const size_t m_MaxBlockCount;
      -
      7151  const VkDeviceSize m_BufferImageGranularity;
      -
      7152  const uint32_t m_FrameInUseCount;
      -
      7153  const bool m_ExplicitBlockSize;
      -
      7154  const uint32_t m_Algorithm;
      -
      7155  const float m_Priority;
      -
      7156  VMA_RW_MUTEX m_Mutex;
      +
      7077  virtual bool CreateAllocationRequest(
      +
      7078  uint32_t currentFrameIndex,
      +
      7079  uint32_t frameInUseCount,
      +
      7080  VkDeviceSize bufferImageGranularity,
      +
      7081  VkDeviceSize allocSize,
      +
      7082  VkDeviceSize allocAlignment,
      +
      7083  bool upperAddress,
      +
      7084  VmaSuballocationType allocType,
      +
      7085  bool canMakeOtherLost,
      +
      7086  uint32_t strategy,
      +
      7087  VmaAllocationRequest* pAllocationRequest);
      +
      7088 
      +
      7089  virtual bool MakeRequestedAllocationsLost(
      +
      7090  uint32_t currentFrameIndex,
      +
      7091  uint32_t frameInUseCount,
      +
      7092  VmaAllocationRequest* pAllocationRequest);
      +
      7093 
      +
      7094  virtual uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);
      +
      7095 
      +
      7096  virtual VkResult CheckCorruption(const void* pBlockData) { return VK_ERROR_FEATURE_NOT_PRESENT; }
      +
      7097 
      +
      7098  virtual void Alloc(
      +
      7099  const VmaAllocationRequest& request,
      +
      7100  VmaSuballocationType type,
      +
      7101  VkDeviceSize allocSize,
      +
      7102  VmaAllocation hAllocation);
      +
      7103 
      +
      7104  virtual void Free(const VmaAllocation allocation) { FreeAtOffset(allocation, allocation->GetOffset()); }
      +
      7105  virtual void FreeAtOffset(VkDeviceSize offset) { FreeAtOffset(VMA_NULL, offset); }
      +
      7106 
      +
      7107 private:
      +
      7108  static const VkDeviceSize MIN_NODE_SIZE = 32;
      +
      7109  static const size_t MAX_LEVELS = 30;
      +
      7110 
      +
      7111  struct ValidationContext
      +
      7112  {
      +
      7113  size_t calculatedAllocationCount;
      +
      7114  size_t calculatedFreeCount;
      +
      7115  VkDeviceSize calculatedSumFreeSize;
      +
      7116 
      +
      7117  ValidationContext() :
      +
      7118  calculatedAllocationCount(0),
      +
      7119  calculatedFreeCount(0),
      +
      7120  calculatedSumFreeSize(0) { }
      +
      7121  };
      +
      7122 
      +
      7123  struct Node
      +
      7124  {
      +
      7125  VkDeviceSize offset;
      +
      7126  enum TYPE
      +
      7127  {
      +
      7128  TYPE_FREE,
      +
      7129  TYPE_ALLOCATION,
      +
      7130  TYPE_SPLIT,
      +
      7131  TYPE_COUNT
      +
      7132  } type;
      +
      7133  Node* parent;
      +
      7134  Node* buddy;
      +
      7135 
      +
      7136  union
      +
      7137  {
      +
      7138  struct
      +
      7139  {
      +
      7140  Node* prev;
      +
      7141  Node* next;
      +
      7142  } free;
      +
      7143  struct
      +
      7144  {
      +
      7145  VmaAllocation alloc;
      +
      7146  } allocation;
      +
      7147  struct
      +
      7148  {
      +
      7149  Node* leftChild;
      +
      7150  } split;
      +
      7151  };
      +
      7152  };
      +
      7153 
      +
      7154  // Size of the memory block aligned down to a power of two.
      +
      7155  VkDeviceSize m_UsableSize;
      +
      7156  uint32_t m_LevelCount;
      7157 
      -
      7158  /* There can be at most one allocation that is completely empty (except when minBlockCount > 0) -
      -
      7159  a hysteresis to avoid pessimistic case of alternating creation and destruction of a VkDeviceMemory. */
      -
      7160  bool m_HasEmptyBlock;
      -
      7161  // Incrementally sorted by sumFreeSize, ascending.
      -
      7162  VmaVector< VmaDeviceMemoryBlock*, VmaStlAllocator<VmaDeviceMemoryBlock*> > m_Blocks;
      -
      7163  uint32_t m_NextBlockId;
      -
      7164 
      -
      7165  VkDeviceSize CalcMaxBlockSize() const;
      -
      7166 
      -
      7167  // Finds and removes given block from vector.
      -
      7168  void Remove(VmaDeviceMemoryBlock* pBlock);
      +
      7158  Node* m_Root;
      +
      7159  struct {
      +
      7160  Node* front;
      +
      7161  Node* back;
      +
      7162  } m_FreeList[MAX_LEVELS];
      +
      7163  // Number of nodes in the tree with type == TYPE_ALLOCATION.
      +
      7164  size_t m_AllocationCount;
      +
      7165  // Number of nodes in the tree with type == TYPE_FREE.
      +
      7166  size_t m_FreeCount;
      +
      7167  // This includes space wasted due to internal fragmentation. Doesn't include unusable size.
      +
      7168  VkDeviceSize m_SumFreeSize;
      7169 
      -
      7170  // Performs single step in sorting m_Blocks. They may not be fully sorted
      -
      7171  // after this call.
      -
      7172  void IncrementallySortBlocks();
      -
      7173 
      -
      7174  VkResult AllocatePage(
      -
      7175  uint32_t currentFrameIndex,
      -
      7176  VkDeviceSize size,
      -
      7177  VkDeviceSize alignment,
      -
      7178  const VmaAllocationCreateInfo& createInfo,
      -
      7179  VmaSuballocationType suballocType,
      -
      7180  VmaAllocation* pAllocation);
      -
      7181 
      -
      7182  // To be used only without CAN_MAKE_OTHER_LOST flag.
      -
      7183  VkResult AllocateFromBlock(
      -
      7184  VmaDeviceMemoryBlock* pBlock,
      -
      7185  uint32_t currentFrameIndex,
      -
      7186  VkDeviceSize size,
      -
      7187  VkDeviceSize alignment,
      -
      7188  VmaAllocationCreateFlags allocFlags,
      -
      7189  void* pUserData,
      -
      7190  VmaSuballocationType suballocType,
      -
      7191  uint32_t strategy,
      -
      7192  VmaAllocation* pAllocation);
      -
      7193 
      -
      7194  VkResult CreateBlock(VkDeviceSize blockSize, size_t* pNewBlockIndex);
      -
      7195 
      -
      7196  // Saves result to pCtx->res.
      -
      7197  void ApplyDefragmentationMovesCpu(
      -
      7198  class VmaBlockVectorDefragmentationContext* pDefragCtx,
      -
      7199  const VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves);
      -
      7200  // Saves result to pCtx->res.
      -
      7201  void ApplyDefragmentationMovesGpu(
      -
      7202  class VmaBlockVectorDefragmentationContext* pDefragCtx,
      -
      7203  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
      -
      7204  VkCommandBuffer commandBuffer);
      +
      7170  VkDeviceSize GetUnusableSize() const { return GetSize() - m_UsableSize; }
      +
      7171  void DeleteNode(Node* node);
      +
      7172  bool ValidateNode(ValidationContext& ctx, const Node* parent, const Node* curr, uint32_t level, VkDeviceSize levelNodeSize) const;
      +
      7173  uint32_t AllocSizeToLevel(VkDeviceSize allocSize) const;
      +
      7174  inline VkDeviceSize LevelToNodeSize(uint32_t level) const { return m_UsableSize >> level; }
      +
      7175  // Alloc passed just for validation. Can be null.
      +
      7176  void FreeAtOffset(VmaAllocation alloc, VkDeviceSize offset);
      +
      7177  void CalcAllocationStatInfoNode(VmaStatInfo& outInfo, const Node* node, VkDeviceSize levelNodeSize) const;
      +
      7178  // Adds node to the front of FreeList at given level.
      +
      7179  // node->type must be FREE.
      +
      7180  // node->free.prev, next can be undefined.
      +
      7181  void AddToFreeListFront(uint32_t level, Node* node);
      +
      7182  // Removes node from FreeList at given level.
      +
      7183  // node->type must be FREE.
      +
      7184  // node->free.prev, next stay untouched.
      +
      7185  void RemoveFromFreeList(uint32_t level, Node* node);
      +
      7186 
      +
      7187 #if VMA_STATS_STRING_ENABLED
      +
      7188  void PrintDetailedMapNode(class VmaJsonWriter& json, const Node* node, VkDeviceSize levelNodeSize) const;
      +
      7189 #endif
      +
      7190 };
      +
      7191 
      +
      7192 /*
      +
      7193 Represents a single block of device memory (`VkDeviceMemory`) with all the
      +
      7194 data about its regions (aka suballocations, #VmaAllocation), assigned and free.
      +
      7195 
      +
      7196 Thread-safety: This class must be externally synchronized.
      +
      7197 */
      +
      7198 class VmaDeviceMemoryBlock
      +
      7199 {
      +
      7200  VMA_CLASS_NO_COPY(VmaDeviceMemoryBlock)
      +
      7201 public:
      +
      7202  VmaBlockMetadata* m_pMetadata;
      +
      7203 
      +
      7204  VmaDeviceMemoryBlock(VmaAllocator hAllocator);
      7205 
      -
      7206  /*
      -
      7207  Used during defragmentation. pDefragmentationStats is optional. It's in/out
      -
      7208  - updated with new data.
      -
      7209  */
      -
      7210  void FreeEmptyBlocks(VmaDefragmentationStats* pDefragmentationStats);
      +
      7206  ~VmaDeviceMemoryBlock()
      +
      7207  {
      +
      7208  VMA_ASSERT(m_MapCount == 0 && "VkDeviceMemory block is being destroyed while it is still mapped.");
      +
      7209  VMA_ASSERT(m_hMemory == VK_NULL_HANDLE);
      +
      7210  }
      7211 
      -
      7212  void UpdateHasEmptyBlock();
      -
      7213 };
      -
      7214 
      -
      7215 struct VmaPool_T
      -
      7216 {
      -
      7217  VMA_CLASS_NO_COPY(VmaPool_T)
      -
      7218 public:
      -
      7219  VmaBlockVector m_BlockVector;
      -
      7220 
      -
      7221  VmaPool_T(
      -
      7222  VmaAllocator hAllocator,
      -
      7223  const VmaPoolCreateInfo& createInfo,
      -
      7224  VkDeviceSize preferredBlockSize);
      -
      7225  ~VmaPool_T();
      -
      7226 
      +
      7212  // Always call after construction.
      +
      7213  void Init(
      +
      7214  VmaAllocator hAllocator,
      +
      7215  VmaPool hParentPool,
      +
      7216  uint32_t newMemoryTypeIndex,
      +
      7217  VkDeviceMemory newMemory,
      +
      7218  VkDeviceSize newSize,
      +
      7219  uint32_t id,
      +
      7220  uint32_t algorithm);
      +
      7221  // Always call before destruction.
      +
      7222  void Destroy(VmaAllocator allocator);
      +
      7223 
      +
      7224  VmaPool GetParentPool() const { return m_hParentPool; }
      +
      7225  VkDeviceMemory GetDeviceMemory() const { return m_hMemory; }
      +
      7226  uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; }
      7227  uint32_t GetId() const { return m_Id; }
      -
      7228  void SetId(uint32_t id) { VMA_ASSERT(m_Id == 0); m_Id = id; }
      +
      7228  void* GetMappedData() const { return m_pMappedData; }
      7229 
      -
      7230  const char* GetName() const { return m_Name; }
      -
      7231  void SetName(const char* pName);
      +
      7230  // Validates all data structures inside this object. If not valid, returns false.
      +
      7231  bool Validate() const;
      7232 
      -
      7233 #if VMA_STATS_STRING_ENABLED
      -
      7234  //void PrintDetailedMap(class VmaStringBuilder& sb);
      -
      7235 #endif
      -
      7236 
      -
      7237 private:
      -
      7238  uint32_t m_Id;
      -
      7239  char* m_Name;
      -
      7240 };
      +
      7233  VkResult CheckCorruption(VmaAllocator hAllocator);
      +
      7234 
      +
      7235  // ppData can be null.
      +
      7236  VkResult Map(VmaAllocator hAllocator, uint32_t count, void** ppData);
      +
      7237  void Unmap(VmaAllocator hAllocator, uint32_t count);
      +
      7238 
      +
      7239  VkResult WriteMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize);
      +
      7240  VkResult ValidateMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize);
      7241 
      -
      7242 /*
      -
      7243 Performs defragmentation:
      -
      7244 
      -
      7245 - Updates `pBlockVector->m_pMetadata`.
      -
      7246 - Updates allocations by calling ChangeBlockAllocation() or ChangeOffset().
      -
      7247 - Does not move actual data, only returns requested moves as `moves`.
      -
      7248 */
      -
      7249 class VmaDefragmentationAlgorithm
      -
      7250 {
      -
      7251  VMA_CLASS_NO_COPY(VmaDefragmentationAlgorithm)
      -
      7252 public:
      -
      7253  VmaDefragmentationAlgorithm(
      -
      7254  VmaAllocator hAllocator,
      -
      7255  VmaBlockVector* pBlockVector,
      -
      7256  uint32_t currentFrameIndex) :
      -
      7257  m_hAllocator(hAllocator),
      -
      7258  m_pBlockVector(pBlockVector),
      -
      7259  m_CurrentFrameIndex(currentFrameIndex)
      -
      7260  {
      -
      7261  }
      -
      7262  virtual ~VmaDefragmentationAlgorithm()
      -
      7263  {
      -
      7264  }
      -
      7265 
      -
      7266  virtual void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged) = 0;
      -
      7267  virtual void AddAll() = 0;
      -
      7268 
      -
      7269  virtual VkResult Defragment(
      -
      7270  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
      -
      7271  VkDeviceSize maxBytesToMove,
      -
      7272  uint32_t maxAllocationsToMove,
      -
      7273  VmaDefragmentationFlags flags) = 0;
      -
      7274 
      -
      7275  virtual VkDeviceSize GetBytesMoved() const = 0;
      -
      7276  virtual uint32_t GetAllocationsMoved() const = 0;
      -
      7277 
      -
      7278 protected:
      -
      7279  VmaAllocator const m_hAllocator;
      -
      7280  VmaBlockVector* const m_pBlockVector;
      -
      7281  const uint32_t m_CurrentFrameIndex;
      +
      7242  VkResult BindBufferMemory(
      +
      7243  const VmaAllocator hAllocator,
      +
      7244  const VmaAllocation hAllocation,
      +
      7245  VkDeviceSize allocationLocalOffset,
      +
      7246  VkBuffer hBuffer,
      +
      7247  const void* pNext);
      +
      7248  VkResult BindImageMemory(
      +
      7249  const VmaAllocator hAllocator,
      +
      7250  const VmaAllocation hAllocation,
      +
      7251  VkDeviceSize allocationLocalOffset,
      +
      7252  VkImage hImage,
      +
      7253  const void* pNext);
      +
      7254 
      +
      7255 private:
      +
      7256  VmaPool m_hParentPool; // VK_NULL_HANDLE if not belongs to custom pool.
      +
      7257  uint32_t m_MemoryTypeIndex;
      +
      7258  uint32_t m_Id;
      +
      7259  VkDeviceMemory m_hMemory;
      +
      7260 
      +
      7261  /*
      +
      7262  Protects access to m_hMemory so it's not used by multiple threads simultaneously, e.g. vkMapMemory, vkBindBufferMemory.
      +
      7263  Also protects m_MapCount, m_pMappedData.
      +
      7264  Allocations, deallocations, any change in m_pMetadata is protected by parent's VmaBlockVector::m_Mutex.
      +
      7265  */
      +
      7266  VMA_MUTEX m_Mutex;
      +
      7267  uint32_t m_MapCount;
      +
      7268  void* m_pMappedData;
      +
      7269 };
      +
      7270 
      +
      7271 struct VmaDefragmentationMove
      +
      7272 {
      +
      7273  size_t srcBlockIndex;
      +
      7274  size_t dstBlockIndex;
      +
      7275  VkDeviceSize srcOffset;
      +
      7276  VkDeviceSize dstOffset;
      +
      7277  VkDeviceSize size;
      +
      7278  VmaAllocation hAllocation;
      +
      7279  VmaDeviceMemoryBlock* pSrcBlock;
      +
      7280  VmaDeviceMemoryBlock* pDstBlock;
      +
      7281 };
      7282 
      -
      7283  struct AllocationInfo
      -
      7284  {
      -
      7285  VmaAllocation m_hAllocation;
      -
      7286  VkBool32* m_pChanged;
      -
      7287 
      -
      7288  AllocationInfo() :
      -
      7289  m_hAllocation(VK_NULL_HANDLE),
      -
      7290  m_pChanged(VMA_NULL)
      -
      7291  {
      -
      7292  }
      -
      7293  AllocationInfo(VmaAllocation hAlloc, VkBool32* pChanged) :
      -
      7294  m_hAllocation(hAlloc),
      -
      7295  m_pChanged(pChanged)
      -
      7296  {
      -
      7297  }
      -
      7298  };
      -
      7299 };
      -
      7300 
      -
      7301 class VmaDefragmentationAlgorithm_Generic : public VmaDefragmentationAlgorithm
      -
      7302 {
      -
      7303  VMA_CLASS_NO_COPY(VmaDefragmentationAlgorithm_Generic)
      -
      7304 public:
      -
      7305  VmaDefragmentationAlgorithm_Generic(
      -
      7306  VmaAllocator hAllocator,
      -
      7307  VmaBlockVector* pBlockVector,
      -
      7308  uint32_t currentFrameIndex,
      -
      7309  bool overlappingMoveSupported);
      -
      7310  virtual ~VmaDefragmentationAlgorithm_Generic();
      -
      7311 
      -
      7312  virtual void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged);
      -
      7313  virtual void AddAll() { m_AllAllocations = true; }
      -
      7314 
      -
      7315  virtual VkResult Defragment(
      -
      7316  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
      -
      7317  VkDeviceSize maxBytesToMove,
      -
      7318  uint32_t maxAllocationsToMove,
      -
      7319  VmaDefragmentationFlags flags);
      -
      7320 
      -
      7321  virtual VkDeviceSize GetBytesMoved() const { return m_BytesMoved; }
      -
      7322  virtual uint32_t GetAllocationsMoved() const { return m_AllocationsMoved; }
      -
      7323 
      -
      7324 private:
      -
      7325  uint32_t m_AllocationCount;
      -
      7326  bool m_AllAllocations;
      -
      7327 
      -
      7328  VkDeviceSize m_BytesMoved;
      -
      7329  uint32_t m_AllocationsMoved;
      -
      7330 
      -
      7331  struct AllocationInfoSizeGreater
      -
      7332  {
      -
      7333  bool operator()(const AllocationInfo& lhs, const AllocationInfo& rhs) const
      -
      7334  {
      -
      7335  return lhs.m_hAllocation->GetSize() > rhs.m_hAllocation->GetSize();
      -
      7336  }
      -
      7337  };
      +
      7283 class VmaDefragmentationAlgorithm;
      +
      7284 
      +
      7285 /*
      +
      7286 Sequence of VmaDeviceMemoryBlock. Represents memory blocks allocated for a specific
      +
      7287 Vulkan memory type.
      +
      7288 
      +
      7289 Synchronized internally with a mutex.
      +
      7290 */
      +
      7291 struct VmaBlockVector
      +
      7292 {
      +
      7293  VMA_CLASS_NO_COPY(VmaBlockVector)
      +
      7294 public:
      +
      7295  VmaBlockVector(
      +
      7296  VmaAllocator hAllocator,
      +
      7297  VmaPool hParentPool,
      +
      7298  uint32_t memoryTypeIndex,
      +
      7299  VkDeviceSize preferredBlockSize,
      +
      7300  size_t minBlockCount,
      +
      7301  size_t maxBlockCount,
      +
      7302  VkDeviceSize bufferImageGranularity,
      +
      7303  uint32_t frameInUseCount,
      +
      7304  bool explicitBlockSize,
      +
      7305  uint32_t algorithm,
      +
      7306  float priority);
      +
      7307  ~VmaBlockVector();
      +
      7308 
      +
      7309  VkResult CreateMinBlocks();
      +
      7310 
      +
      7311  VmaAllocator GetAllocator() const { return m_hAllocator; }
      +
      7312  VmaPool GetParentPool() const { return m_hParentPool; }
      +
      7313  bool IsCustomPool() const { return m_hParentPool != VMA_NULL; }
      +
      7314  uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; }
      +
      7315  VkDeviceSize GetPreferredBlockSize() const { return m_PreferredBlockSize; }
      +
      7316  VkDeviceSize GetBufferImageGranularity() const { return m_BufferImageGranularity; }
      +
      7317  uint32_t GetFrameInUseCount() const { return m_FrameInUseCount; }
      +
      7318  uint32_t GetAlgorithm() const { return m_Algorithm; }
      +
      7319 
      +
      7320  void GetPoolStats(VmaPoolStats* pStats);
      +
      7321 
      +
      7322  bool IsEmpty();
      +
      7323  bool IsCorruptionDetectionEnabled() const;
      +
      7324 
      +
      7325  VkResult Allocate(
      +
      7326  uint32_t currentFrameIndex,
      +
      7327  VkDeviceSize size,
      +
      7328  VkDeviceSize alignment,
      +
      7329  const VmaAllocationCreateInfo& createInfo,
      +
      7330  VmaSuballocationType suballocType,
      +
      7331  size_t allocationCount,
      +
      7332  VmaAllocation* pAllocations);
      +
      7333 
      +
      7334  void Free(const VmaAllocation hAllocation);
      +
      7335 
      +
      7336  // Adds statistics of this BlockVector to pStats.
      +
      7337  void AddStats(VmaStats* pStats);
      7338 
      -
      7339  struct AllocationInfoOffsetGreater
      -
      7340  {
      -
      7341  bool operator()(const AllocationInfo& lhs, const AllocationInfo& rhs) const
      -
      7342  {
      -
      7343  return lhs.m_hAllocation->GetOffset() > rhs.m_hAllocation->GetOffset();
      -
      7344  }
      -
      7345  };
      -
      7346 
      -
      7347  struct BlockInfo
      -
      7348  {
      -
      7349  size_t m_OriginalBlockIndex;
      -
      7350  VmaDeviceMemoryBlock* m_pBlock;
      -
      7351  bool m_HasNonMovableAllocations;
      -
      7352  VmaVector< AllocationInfo, VmaStlAllocator<AllocationInfo> > m_Allocations;
      -
      7353 
      -
      7354  BlockInfo(const VkAllocationCallbacks* pAllocationCallbacks) :
      -
      7355  m_OriginalBlockIndex(SIZE_MAX),
      -
      7356  m_pBlock(VMA_NULL),
      -
      7357  m_HasNonMovableAllocations(true),
      -
      7358  m_Allocations(pAllocationCallbacks)
      -
      7359  {
      -
      7360  }
      -
      7361 
      -
      7362  void CalcHasNonMovableAllocations()
      -
      7363  {
      -
      7364  const size_t blockAllocCount = m_pBlock->m_pMetadata->GetAllocationCount();
      -
      7365  const size_t defragmentAllocCount = m_Allocations.size();
      -
      7366  m_HasNonMovableAllocations = blockAllocCount != defragmentAllocCount;
      -
      7367  }
      -
      7368 
      -
      7369  void SortAllocationsBySizeDescending()
      -
      7370  {
      -
      7371  VMA_SORT(m_Allocations.begin(), m_Allocations.end(), AllocationInfoSizeGreater());
      -
      7372  }
      -
      7373 
      -
      7374  void SortAllocationsByOffsetDescending()
      -
      7375  {
      -
      7376  VMA_SORT(m_Allocations.begin(), m_Allocations.end(), AllocationInfoOffsetGreater());
      -
      7377  }
      -
      7378  };
      -
      7379 
      -
      7380  struct BlockPointerLess
      -
      7381  {
      -
      7382  bool operator()(const BlockInfo* pLhsBlockInfo, const VmaDeviceMemoryBlock* pRhsBlock) const
      -
      7383  {
      -
      7384  return pLhsBlockInfo->m_pBlock < pRhsBlock;
      -
      7385  }
      -
      7386  bool operator()(const BlockInfo* pLhsBlockInfo, const BlockInfo* pRhsBlockInfo) const
      -
      7387  {
      -
      7388  return pLhsBlockInfo->m_pBlock < pRhsBlockInfo->m_pBlock;
      -
      7389  }
      -
      7390  };
      +
      7339 #if VMA_STATS_STRING_ENABLED
      +
      7340  void PrintDetailedMap(class VmaJsonWriter& json);
      +
      7341 #endif
      +
      7342 
      +
      7343  void MakePoolAllocationsLost(
      +
      7344  uint32_t currentFrameIndex,
      +
      7345  size_t* pLostAllocationCount);
      +
      7346  VkResult CheckCorruption();
      +
      7347 
      +
      7348  // Saves results in pCtx->res.
      +
      7349  void Defragment(
      +
      7350  class VmaBlockVectorDefragmentationContext* pCtx,
      + +
      7352  VkDeviceSize& maxCpuBytesToMove, uint32_t& maxCpuAllocationsToMove,
      +
      7353  VkDeviceSize& maxGpuBytesToMove, uint32_t& maxGpuAllocationsToMove,
      +
      7354  VkCommandBuffer commandBuffer);
      +
      7355  void DefragmentationEnd(
      +
      7356  class VmaBlockVectorDefragmentationContext* pCtx,
      +
      7357  uint32_t flags,
      +
      7358  VmaDefragmentationStats* pStats);
      +
      7359 
      +
      7360  uint32_t ProcessDefragmentations(
      +
      7361  class VmaBlockVectorDefragmentationContext *pCtx,
      +
      7362  VmaDefragmentationPassMoveInfo* pMove, uint32_t maxMoves);
      +
      7363 
      +
      7364  void CommitDefragmentations(
      +
      7365  class VmaBlockVectorDefragmentationContext *pCtx,
      +
      7366  VmaDefragmentationStats* pStats);
      +
      7367 
      +
      7369  // To be used only while the m_Mutex is locked. Used during defragmentation.
      +
      7370 
      +
      7371  size_t GetBlockCount() const { return m_Blocks.size(); }
      +
      7372  VmaDeviceMemoryBlock* GetBlock(size_t index) const { return m_Blocks[index]; }
      +
      7373  size_t CalcAllocationCount() const;
      +
      7374  bool IsBufferImageGranularityConflictPossible() const;
      +
      7375 
      +
      7376 private:
      +
      7377  friend class VmaDefragmentationAlgorithm_Generic;
      +
      7378 
      +
      7379  const VmaAllocator m_hAllocator;
      +
      7380  const VmaPool m_hParentPool;
      +
      7381  const uint32_t m_MemoryTypeIndex;
      +
      7382  const VkDeviceSize m_PreferredBlockSize;
      +
      7383  const size_t m_MinBlockCount;
      +
      7384  const size_t m_MaxBlockCount;
      +
      7385  const VkDeviceSize m_BufferImageGranularity;
      +
      7386  const uint32_t m_FrameInUseCount;
      +
      7387  const bool m_ExplicitBlockSize;
      +
      7388  const uint32_t m_Algorithm;
      +
      7389  const float m_Priority;
      +
      7390  VMA_RW_MUTEX m_Mutex;
      7391 
      -
      7392  // 1. Blocks with some non-movable allocations go first.
      -
      7393  // 2. Blocks with smaller sumFreeSize go first.
      -
      7394  struct BlockInfoCompareMoveDestination
      -
      7395  {
      -
      7396  bool operator()(const BlockInfo* pLhsBlockInfo, const BlockInfo* pRhsBlockInfo) const
      -
      7397  {
      -
      7398  if(pLhsBlockInfo->m_HasNonMovableAllocations && !pRhsBlockInfo->m_HasNonMovableAllocations)
      -
      7399  {
      -
      7400  return true;
      -
      7401  }
      -
      7402  if(!pLhsBlockInfo->m_HasNonMovableAllocations && pRhsBlockInfo->m_HasNonMovableAllocations)
      -
      7403  {
      -
      7404  return false;
      -
      7405  }
      -
      7406  if(pLhsBlockInfo->m_pBlock->m_pMetadata->GetSumFreeSize() < pRhsBlockInfo->m_pBlock->m_pMetadata->GetSumFreeSize())
      -
      7407  {
      -
      7408  return true;
      -
      7409  }
      -
      7410  return false;
      -
      7411  }
      -
      7412  };
      -
      7413 
      -
      7414  typedef VmaVector< BlockInfo*, VmaStlAllocator<BlockInfo*> > BlockInfoVector;
      -
      7415  BlockInfoVector m_Blocks;
      -
      7416 
      -
      7417  VkResult DefragmentRound(
      -
      7418  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
      -
      7419  VkDeviceSize maxBytesToMove,
      -
      7420  uint32_t maxAllocationsToMove,
      -
      7421  bool freeOldAllocations);
      -
      7422 
      -
      7423  size_t CalcBlocksWithNonMovableCount() const;
      -
      7424 
      -
      7425  static bool MoveMakesSense(
      -
      7426  size_t dstBlockIndex, VkDeviceSize dstOffset,
      -
      7427  size_t srcBlockIndex, VkDeviceSize srcOffset);
      -
      7428 };
      +
      7392  /* There can be at most one allocation that is completely empty (except when minBlockCount > 0) -
      +
      7393  a hysteresis to avoid pessimistic case of alternating creation and destruction of a VkDeviceMemory. */
      +
      7394  bool m_HasEmptyBlock;
      +
      7395  // Incrementally sorted by sumFreeSize, ascending.
      +
      7396  VmaVector< VmaDeviceMemoryBlock*, VmaStlAllocator<VmaDeviceMemoryBlock*> > m_Blocks;
      +
      7397  uint32_t m_NextBlockId;
      +
      7398 
      +
      7399  VkDeviceSize CalcMaxBlockSize() const;
      +
      7400 
      +
      7401  // Finds and removes given block from vector.
      +
      7402  void Remove(VmaDeviceMemoryBlock* pBlock);
      +
      7403 
      +
      7404  // Performs single step in sorting m_Blocks. They may not be fully sorted
      +
      7405  // after this call.
      +
      7406  void IncrementallySortBlocks();
      +
      7407 
      +
      7408  VkResult AllocatePage(
      +
      7409  uint32_t currentFrameIndex,
      +
      7410  VkDeviceSize size,
      +
      7411  VkDeviceSize alignment,
      +
      7412  const VmaAllocationCreateInfo& createInfo,
      +
      7413  VmaSuballocationType suballocType,
      +
      7414  VmaAllocation* pAllocation);
      +
      7415 
      +
      7416  // To be used only without CAN_MAKE_OTHER_LOST flag.
      +
      7417  VkResult AllocateFromBlock(
      +
      7418  VmaDeviceMemoryBlock* pBlock,
      +
      7419  uint32_t currentFrameIndex,
      +
      7420  VkDeviceSize size,
      +
      7421  VkDeviceSize alignment,
      +
      7422  VmaAllocationCreateFlags allocFlags,
      +
      7423  void* pUserData,
      +
      7424  VmaSuballocationType suballocType,
      +
      7425  uint32_t strategy,
      +
      7426  VmaAllocation* pAllocation);
      +
      7427 
      +
      7428  VkResult CreateBlock(VkDeviceSize blockSize, size_t* pNewBlockIndex);
      7429 
      -
      7430 class VmaDefragmentationAlgorithm_Fast : public VmaDefragmentationAlgorithm
      -
      7431 {
      -
      7432  VMA_CLASS_NO_COPY(VmaDefragmentationAlgorithm_Fast)
      -
      7433 public:
      -
      7434  VmaDefragmentationAlgorithm_Fast(
      -
      7435  VmaAllocator hAllocator,
      -
      7436  VmaBlockVector* pBlockVector,
      -
      7437  uint32_t currentFrameIndex,
      -
      7438  bool overlappingMoveSupported);
      -
      7439  virtual ~VmaDefragmentationAlgorithm_Fast();
      -
      7440 
      -
      7441  virtual void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged) { ++m_AllocationCount; }
      -
      7442  virtual void AddAll() { m_AllAllocations = true; }
      -
      7443 
      -
      7444  virtual VkResult Defragment(
      -
      7445  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
      -
      7446  VkDeviceSize maxBytesToMove,
      -
      7447  uint32_t maxAllocationsToMove,
      -
      7448  VmaDefragmentationFlags flags);
      -
      7449 
      -
      7450  virtual VkDeviceSize GetBytesMoved() const { return m_BytesMoved; }
      -
      7451  virtual uint32_t GetAllocationsMoved() const { return m_AllocationsMoved; }
      -
      7452 
      -
      7453 private:
      -
      7454  struct BlockInfo
      -
      7455  {
      -
      7456  size_t origBlockIndex;
      -
      7457  };
      -
      7458 
      -
      7459  class FreeSpaceDatabase
      -
      7460  {
      -
      7461  public:
      -
      7462  FreeSpaceDatabase()
      -
      7463  {
      -
      7464  FreeSpace s = {};
      -
      7465  s.blockInfoIndex = SIZE_MAX;
      -
      7466  for(size_t i = 0; i < MAX_COUNT; ++i)
      -
      7467  {
      -
      7468  m_FreeSpaces[i] = s;
      -
      7469  }
      -
      7470  }
      -
      7471 
      -
      7472  void Register(size_t blockInfoIndex, VkDeviceSize offset, VkDeviceSize size)
      -
      7473  {
      -
      7474  if(size < VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
      -
      7475  {
      -
      7476  return;
      -
      7477  }
      +
      7430  // Saves result to pCtx->res.
      +
      7431  void ApplyDefragmentationMovesCpu(
      +
      7432  class VmaBlockVectorDefragmentationContext* pDefragCtx,
      +
      7433  const VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves);
      +
      7434  // Saves result to pCtx->res.
      +
      7435  void ApplyDefragmentationMovesGpu(
      +
      7436  class VmaBlockVectorDefragmentationContext* pDefragCtx,
      +
      7437  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
      +
      7438  VkCommandBuffer commandBuffer);
      +
      7439 
      +
      7440  /*
      +
      7441  Used during defragmentation. pDefragmentationStats is optional. It's in/out
      +
      7442  - updated with new data.
      +
      7443  */
      +
      7444  void FreeEmptyBlocks(VmaDefragmentationStats* pDefragmentationStats);
      +
      7445 
      +
      7446  void UpdateHasEmptyBlock();
      +
      7447 };
      +
      7448 
      +
      7449 struct VmaPool_T
      +
      7450 {
      +
      7451  VMA_CLASS_NO_COPY(VmaPool_T)
      +
      7452 public:
      +
      7453  VmaBlockVector m_BlockVector;
      +
      7454 
      +
      7455  VmaPool_T(
      +
      7456  VmaAllocator hAllocator,
      +
      7457  const VmaPoolCreateInfo& createInfo,
      +
      7458  VkDeviceSize preferredBlockSize);
      +
      7459  ~VmaPool_T();
      +
      7460 
      +
      7461  uint32_t GetId() const { return m_Id; }
      +
      7462  void SetId(uint32_t id) { VMA_ASSERT(m_Id == 0); m_Id = id; }
      +
      7463 
      +
      7464  const char* GetName() const { return m_Name; }
      +
      7465  void SetName(const char* pName);
      +
      7466 
      +
      7467 #if VMA_STATS_STRING_ENABLED
      +
      7468  //void PrintDetailedMap(class VmaStringBuilder& sb);
      +
      7469 #endif
      +
      7470 
      +
      7471 private:
      +
      7472  uint32_t m_Id;
      +
      7473  char* m_Name;
      +
      7474  VmaPool_T* m_PrevPool = VMA_NULL;
      +
      7475  VmaPool_T* m_NextPool = VMA_NULL;
      +
      7476  friend struct VmaPoolListItemTraits;
      +
      7477 };
      7478 
      -
      7479  // Find first invalid or the smallest structure.
      -
      7480  size_t bestIndex = SIZE_MAX;
      -
      7481  for(size_t i = 0; i < MAX_COUNT; ++i)
      -
      7482  {
      -
      7483  // Empty structure.
      -
      7484  if(m_FreeSpaces[i].blockInfoIndex == SIZE_MAX)
      -
      7485  {
      -
      7486  bestIndex = i;
      -
      7487  break;
      -
      7488  }
      -
      7489  if(m_FreeSpaces[i].size < size &&
      -
      7490  (bestIndex == SIZE_MAX || m_FreeSpaces[bestIndex].size > m_FreeSpaces[i].size))
      -
      7491  {
      -
      7492  bestIndex = i;
      -
      7493  }
      -
      7494  }
      -
      7495 
      -
      7496  if(bestIndex != SIZE_MAX)
      -
      7497  {
      -
      7498  m_FreeSpaces[bestIndex].blockInfoIndex = blockInfoIndex;
      -
      7499  m_FreeSpaces[bestIndex].offset = offset;
      -
      7500  m_FreeSpaces[bestIndex].size = size;
      -
      7501  }
      -
      7502  }
      -
      7503 
      -
      7504  bool Fetch(VkDeviceSize alignment, VkDeviceSize size,
      -
      7505  size_t& outBlockInfoIndex, VkDeviceSize& outDstOffset)
      -
      7506  {
      -
      7507  size_t bestIndex = SIZE_MAX;
      -
      7508  VkDeviceSize bestFreeSpaceAfter = 0;
      -
      7509  for(size_t i = 0; i < MAX_COUNT; ++i)
      -
      7510  {
      -
      7511  // Structure is valid.
      -
      7512  if(m_FreeSpaces[i].blockInfoIndex != SIZE_MAX)
      -
      7513  {
      -
      7514  const VkDeviceSize dstOffset = VmaAlignUp(m_FreeSpaces[i].offset, alignment);
      -
      7515  // Allocation fits into this structure.
      -
      7516  if(dstOffset + size <= m_FreeSpaces[i].offset + m_FreeSpaces[i].size)
      -
      7517  {
      -
      7518  const VkDeviceSize freeSpaceAfter = (m_FreeSpaces[i].offset + m_FreeSpaces[i].size) -
      -
      7519  (dstOffset + size);
      -
      7520  if(bestIndex == SIZE_MAX || freeSpaceAfter > bestFreeSpaceAfter)
      -
      7521  {
      -
      7522  bestIndex = i;
      -
      7523  bestFreeSpaceAfter = freeSpaceAfter;
      -
      7524  }
      -
      7525  }
      -
      7526  }
      -
      7527  }
      +
      7479 struct VmaPoolListItemTraits
      +
      7480 {
      +
      7481  typedef VmaPool_T ItemType;
      +
      7482  static ItemType* GetPrev(const ItemType* item) { return item->m_PrevPool; }
      +
      7483  static ItemType* GetNext(const ItemType* item) { return item->m_NextPool; }
      +
      7484  static ItemType*& AccessPrev(ItemType* item) { return item->m_PrevPool; }
      +
      7485  static ItemType*& AccessNext(ItemType* item) { return item->m_NextPool; }
      +
      7486 };
      +
      7487 
      +
      7488 /*
      +
      7489 Performs defragmentation:
      +
      7490 
      +
      7491 - Updates `pBlockVector->m_pMetadata`.
      +
      7492 - Updates allocations by calling ChangeBlockAllocation() or ChangeOffset().
      +
      7493 - Does not move actual data, only returns requested moves as `moves`.
      +
      7494 */
      +
      7495 class VmaDefragmentationAlgorithm
      +
      7496 {
      +
      7497  VMA_CLASS_NO_COPY(VmaDefragmentationAlgorithm)
      +
      7498 public:
      +
      7499  VmaDefragmentationAlgorithm(
      +
      7500  VmaAllocator hAllocator,
      +
      7501  VmaBlockVector* pBlockVector,
      +
      7502  uint32_t currentFrameIndex) :
      +
      7503  m_hAllocator(hAllocator),
      +
      7504  m_pBlockVector(pBlockVector),
      +
      7505  m_CurrentFrameIndex(currentFrameIndex)
      +
      7506  {
      +
      7507  }
      +
      7508  virtual ~VmaDefragmentationAlgorithm()
      +
      7509  {
      +
      7510  }
      +
      7511 
      +
      7512  virtual void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged) = 0;
      +
      7513  virtual void AddAll() = 0;
      +
      7514 
      +
      7515  virtual VkResult Defragment(
      +
      7516  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
      +
      7517  VkDeviceSize maxBytesToMove,
      +
      7518  uint32_t maxAllocationsToMove,
      +
      7519  VmaDefragmentationFlags flags) = 0;
      +
      7520 
      +
      7521  virtual VkDeviceSize GetBytesMoved() const = 0;
      +
      7522  virtual uint32_t GetAllocationsMoved() const = 0;
      +
      7523 
      +
      7524 protected:
      +
      7525  VmaAllocator const m_hAllocator;
      +
      7526  VmaBlockVector* const m_pBlockVector;
      +
      7527  const uint32_t m_CurrentFrameIndex;
      7528 
      -
      7529  if(bestIndex != SIZE_MAX)
      -
      7530  {
      -
      7531  outBlockInfoIndex = m_FreeSpaces[bestIndex].blockInfoIndex;
      -
      7532  outDstOffset = VmaAlignUp(m_FreeSpaces[bestIndex].offset, alignment);
      +
      7529  struct AllocationInfo
      +
      7530  {
      +
      7531  VmaAllocation m_hAllocation;
      +
      7532  VkBool32* m_pChanged;
      7533 
      -
      7534  if(bestFreeSpaceAfter >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
      -
      7535  {
      -
      7536  // Leave this structure for remaining empty space.
      -
      7537  const VkDeviceSize alignmentPlusSize = (outDstOffset - m_FreeSpaces[bestIndex].offset) + size;
      -
      7538  m_FreeSpaces[bestIndex].offset += alignmentPlusSize;
      -
      7539  m_FreeSpaces[bestIndex].size -= alignmentPlusSize;
      -
      7540  }
      -
      7541  else
      -
      7542  {
      -
      7543  // This structure becomes invalid.
      -
      7544  m_FreeSpaces[bestIndex].blockInfoIndex = SIZE_MAX;
      -
      7545  }
      +
      7534  AllocationInfo() :
      +
      7535  m_hAllocation(VK_NULL_HANDLE),
      +
      7536  m_pChanged(VMA_NULL)
      +
      7537  {
      +
      7538  }
      +
      7539  AllocationInfo(VmaAllocation hAlloc, VkBool32* pChanged) :
      +
      7540  m_hAllocation(hAlloc),
      +
      7541  m_pChanged(pChanged)
      +
      7542  {
      +
      7543  }
      +
      7544  };
      +
      7545 };
      7546 
      -
      7547  return true;
      -
      7548  }
      -
      7549 
      -
      7550  return false;
      -
      7551  }
      -
      7552 
      -
      7553  private:
      -
      7554  static const size_t MAX_COUNT = 4;
      -
      7555 
      -
      7556  struct FreeSpace
      -
      7557  {
      -
      7558  size_t blockInfoIndex; // SIZE_MAX means this structure is invalid.
      -
      7559  VkDeviceSize offset;
      -
      7560  VkDeviceSize size;
      -
      7561  } m_FreeSpaces[MAX_COUNT];
      -
      7562  };
      -
      7563 
      -
      7564  const bool m_OverlappingMoveSupported;
      -
      7565 
      -
      7566  uint32_t m_AllocationCount;
      -
      7567  bool m_AllAllocations;
      -
      7568 
      -
      7569  VkDeviceSize m_BytesMoved;
      -
      7570  uint32_t m_AllocationsMoved;
      -
      7571 
      -
      7572  VmaVector< BlockInfo, VmaStlAllocator<BlockInfo> > m_BlockInfos;
      +
      7547 class VmaDefragmentationAlgorithm_Generic : public VmaDefragmentationAlgorithm
      +
      7548 {
      +
      7549  VMA_CLASS_NO_COPY(VmaDefragmentationAlgorithm_Generic)
      +
      7550 public:
      +
      7551  VmaDefragmentationAlgorithm_Generic(
      +
      7552  VmaAllocator hAllocator,
      +
      7553  VmaBlockVector* pBlockVector,
      +
      7554  uint32_t currentFrameIndex,
      +
      7555  bool overlappingMoveSupported);
      +
      7556  virtual ~VmaDefragmentationAlgorithm_Generic();
      +
      7557 
      +
      7558  virtual void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged);
      +
      7559  virtual void AddAll() { m_AllAllocations = true; }
      +
      7560 
      +
      7561  virtual VkResult Defragment(
      +
      7562  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
      +
      7563  VkDeviceSize maxBytesToMove,
      +
      7564  uint32_t maxAllocationsToMove,
      +
      7565  VmaDefragmentationFlags flags);
      +
      7566 
      +
      7567  virtual VkDeviceSize GetBytesMoved() const { return m_BytesMoved; }
      +
      7568  virtual uint32_t GetAllocationsMoved() const { return m_AllocationsMoved; }
      +
      7569 
      +
      7570 private:
      +
      7571  uint32_t m_AllocationCount;
      +
      7572  bool m_AllAllocations;
      7573 
      -
      7574  void PreprocessMetadata();
      -
      7575  void PostprocessMetadata();
      -
      7576  void InsertSuballoc(VmaBlockMetadata_Generic* pMetadata, const VmaSuballocation& suballoc);
      -
      7577 };
      -
      7578 
      -
      7579 struct VmaBlockDefragmentationContext
      -
      7580 {
      -
      7581  enum BLOCK_FLAG
      -
      7582  {
      -
      7583  BLOCK_FLAG_USED = 0x00000001,
      -
      7584  };
      -
      7585  uint32_t flags;
      -
      7586  VkBuffer hBuffer;
      -
      7587 };
      -
      7588 
      -
      7589 class VmaBlockVectorDefragmentationContext
      -
      7590 {
      -
      7591  VMA_CLASS_NO_COPY(VmaBlockVectorDefragmentationContext)
      -
      7592 public:
      -
      7593  VkResult res;
      -
      7594  bool mutexLocked;
      -
      7595  VmaVector< VmaBlockDefragmentationContext, VmaStlAllocator<VmaBlockDefragmentationContext> > blockContexts;
      -
      7596  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> > defragmentationMoves;
      -
      7597  uint32_t defragmentationMovesProcessed;
      -
      7598  uint32_t defragmentationMovesCommitted;
      -
      7599  bool hasDefragmentationPlan;
      -
      7600 
      -
      7601  VmaBlockVectorDefragmentationContext(
      -
      7602  VmaAllocator hAllocator,
      -
      7603  VmaPool hCustomPool, // Optional.
      -
      7604  VmaBlockVector* pBlockVector,
      -
      7605  uint32_t currFrameIndex);
      -
      7606  ~VmaBlockVectorDefragmentationContext();
      +
      7574  VkDeviceSize m_BytesMoved;
      +
      7575  uint32_t m_AllocationsMoved;
      +
      7576 
      +
      7577  struct AllocationInfoSizeGreater
      +
      7578  {
      +
      7579  bool operator()(const AllocationInfo& lhs, const AllocationInfo& rhs) const
      +
      7580  {
      +
      7581  return lhs.m_hAllocation->GetSize() > rhs.m_hAllocation->GetSize();
      +
      7582  }
      +
      7583  };
      +
      7584 
      +
      7585  struct AllocationInfoOffsetGreater
      +
      7586  {
      +
      7587  bool operator()(const AllocationInfo& lhs, const AllocationInfo& rhs) const
      +
      7588  {
      +
      7589  return lhs.m_hAllocation->GetOffset() > rhs.m_hAllocation->GetOffset();
      +
      7590  }
      +
      7591  };
      +
      7592 
      +
      7593  struct BlockInfo
      +
      7594  {
      +
      7595  size_t m_OriginalBlockIndex;
      +
      7596  VmaDeviceMemoryBlock* m_pBlock;
      +
      7597  bool m_HasNonMovableAllocations;
      +
      7598  VmaVector< AllocationInfo, VmaStlAllocator<AllocationInfo> > m_Allocations;
      +
      7599 
      +
      7600  BlockInfo(const VkAllocationCallbacks* pAllocationCallbacks) :
      +
      7601  m_OriginalBlockIndex(SIZE_MAX),
      +
      7602  m_pBlock(VMA_NULL),
      +
      7603  m_HasNonMovableAllocations(true),
      +
      7604  m_Allocations(pAllocationCallbacks)
      +
      7605  {
      +
      7606  }
      7607 
      -
      7608  VmaPool GetCustomPool() const { return m_hCustomPool; }
      -
      7609  VmaBlockVector* GetBlockVector() const { return m_pBlockVector; }
      -
      7610  VmaDefragmentationAlgorithm* GetAlgorithm() const { return m_pAlgorithm; }
      -
      7611 
      -
      7612  void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged);
      -
      7613  void AddAll() { m_AllAllocations = true; }
      +
      7608  void CalcHasNonMovableAllocations()
      +
      7609  {
      +
      7610  const size_t blockAllocCount = m_pBlock->m_pMetadata->GetAllocationCount();
      +
      7611  const size_t defragmentAllocCount = m_Allocations.size();
      +
      7612  m_HasNonMovableAllocations = blockAllocCount != defragmentAllocCount;
      +
      7613  }
      7614 
      -
      7615  void Begin(bool overlappingMoveSupported, VmaDefragmentationFlags flags);
      -
      7616 
      -
      7617 private:
      -
      7618  const VmaAllocator m_hAllocator;
      -
      7619  // Null if not from custom pool.
      -
      7620  const VmaPool m_hCustomPool;
      -
      7621  // Redundant, for convenience not to fetch from m_hCustomPool->m_BlockVector or m_hAllocator->m_pBlockVectors.
      -
      7622  VmaBlockVector* const m_pBlockVector;
      -
      7623  const uint32_t m_CurrFrameIndex;
      -
      7624  // Owner of this object.
      -
      7625  VmaDefragmentationAlgorithm* m_pAlgorithm;
      -
      7626 
      -
      7627  struct AllocInfo
      -
      7628  {
      -
      7629  VmaAllocation hAlloc;
      -
      7630  VkBool32* pChanged;
      -
      7631  };
      -
      7632  // Used between constructor and Begin.
      -
      7633  VmaVector< AllocInfo, VmaStlAllocator<AllocInfo> > m_Allocations;
      -
      7634  bool m_AllAllocations;
      -
      7635 };
      -
      7636 
      -
      7637 struct VmaDefragmentationContext_T
      -
      7638 {
      -
      7639 private:
      -
      7640  VMA_CLASS_NO_COPY(VmaDefragmentationContext_T)
      -
      7641 public:
      -
      7642  VmaDefragmentationContext_T(
      -
      7643  VmaAllocator hAllocator,
      -
      7644  uint32_t currFrameIndex,
      -
      7645  uint32_t flags,
      -
      7646  VmaDefragmentationStats* pStats);
      -
      7647  ~VmaDefragmentationContext_T();
      -
      7648 
      -
      7649  void AddPools(uint32_t poolCount, const VmaPool* pPools);
      -
      7650  void AddAllocations(
      -
      7651  uint32_t allocationCount,
      -
      7652  const VmaAllocation* pAllocations,
      -
      7653  VkBool32* pAllocationsChanged);
      -
      7654 
      -
      7655  /*
      -
      7656  Returns:
      -
      7657  - `VK_SUCCESS` if succeeded and object can be destroyed immediately.
      -
      7658  - `VK_NOT_READY` if succeeded but the object must remain alive until vmaDefragmentationEnd().
      -
      7659  - Negative value if error occured and object can be destroyed immediately.
      -
      7660  */
      -
      7661  VkResult Defragment(
      -
      7662  VkDeviceSize maxCpuBytesToMove, uint32_t maxCpuAllocationsToMove,
      -
      7663  VkDeviceSize maxGpuBytesToMove, uint32_t maxGpuAllocationsToMove,
      -
      7664  VkCommandBuffer commandBuffer, VmaDefragmentationStats* pStats, VmaDefragmentationFlags flags);
      -
      7665 
      -
      7666  VkResult DefragmentPassBegin(VmaDefragmentationPassInfo* pInfo);
      -
      7667  VkResult DefragmentPassEnd();
      +
      7615  void SortAllocationsBySizeDescending()
      +
      7616  {
      +
      7617  VMA_SORT(m_Allocations.begin(), m_Allocations.end(), AllocationInfoSizeGreater());
      +
      7618  }
      +
      7619 
      +
      7620  void SortAllocationsByOffsetDescending()
      +
      7621  {
      +
      7622  VMA_SORT(m_Allocations.begin(), m_Allocations.end(), AllocationInfoOffsetGreater());
      +
      7623  }
      +
      7624  };
      +
      7625 
      +
      7626  struct BlockPointerLess
      +
      7627  {
      +
      7628  bool operator()(const BlockInfo* pLhsBlockInfo, const VmaDeviceMemoryBlock* pRhsBlock) const
      +
      7629  {
      +
      7630  return pLhsBlockInfo->m_pBlock < pRhsBlock;
      +
      7631  }
      +
      7632  bool operator()(const BlockInfo* pLhsBlockInfo, const BlockInfo* pRhsBlockInfo) const
      +
      7633  {
      +
      7634  return pLhsBlockInfo->m_pBlock < pRhsBlockInfo->m_pBlock;
      +
      7635  }
      +
      7636  };
      +
      7637 
      +
      7638  // 1. Blocks with some non-movable allocations go first.
      +
      7639  // 2. Blocks with smaller sumFreeSize go first.
      +
      7640  struct BlockInfoCompareMoveDestination
      +
      7641  {
      +
      7642  bool operator()(const BlockInfo* pLhsBlockInfo, const BlockInfo* pRhsBlockInfo) const
      +
      7643  {
      +
      7644  if(pLhsBlockInfo->m_HasNonMovableAllocations && !pRhsBlockInfo->m_HasNonMovableAllocations)
      +
      7645  {
      +
      7646  return true;
      +
      7647  }
      +
      7648  if(!pLhsBlockInfo->m_HasNonMovableAllocations && pRhsBlockInfo->m_HasNonMovableAllocations)
      +
      7649  {
      +
      7650  return false;
      +
      7651  }
      +
      7652  if(pLhsBlockInfo->m_pBlock->m_pMetadata->GetSumFreeSize() < pRhsBlockInfo->m_pBlock->m_pMetadata->GetSumFreeSize())
      +
      7653  {
      +
      7654  return true;
      +
      7655  }
      +
      7656  return false;
      +
      7657  }
      +
      7658  };
      +
      7659 
      +
      7660  typedef VmaVector< BlockInfo*, VmaStlAllocator<BlockInfo*> > BlockInfoVector;
      +
      7661  BlockInfoVector m_Blocks;
      +
      7662 
      +
      7663  VkResult DefragmentRound(
      +
      7664  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
      +
      7665  VkDeviceSize maxBytesToMove,
      +
      7666  uint32_t maxAllocationsToMove,
      +
      7667  bool freeOldAllocations);
      7668 
      -
      7669 private:
      -
      7670  const VmaAllocator m_hAllocator;
      -
      7671  const uint32_t m_CurrFrameIndex;
      -
      7672  const uint32_t m_Flags;
      -
      7673  VmaDefragmentationStats* const m_pStats;
      -
      7674 
      -
      7675  VkDeviceSize m_MaxCpuBytesToMove;
      -
      7676  uint32_t m_MaxCpuAllocationsToMove;
      -
      7677  VkDeviceSize m_MaxGpuBytesToMove;
      -
      7678  uint32_t m_MaxGpuAllocationsToMove;
      -
      7679 
      -
      7680  // Owner of these objects.
      -
      7681  VmaBlockVectorDefragmentationContext* m_DefaultPoolContexts[VK_MAX_MEMORY_TYPES];
      -
      7682  // Owner of these objects.
      -
      7683  VmaVector< VmaBlockVectorDefragmentationContext*, VmaStlAllocator<VmaBlockVectorDefragmentationContext*> > m_CustomPoolContexts;
      -
      7684 };
      -
      7685 
      -
      7686 #if VMA_RECORDING_ENABLED
      -
      7687 
      -
      7688 class VmaRecorder
      -
      7689 {
      -
      7690 public:
      -
      7691  VmaRecorder();
      -
      7692  VkResult Init(const VmaRecordSettings& settings, bool useMutex);
      -
      7693  void WriteConfiguration(
      -
      7694  const VkPhysicalDeviceProperties& devProps,
      -
      7695  const VkPhysicalDeviceMemoryProperties& memProps,
      -
      7696  uint32_t vulkanApiVersion,
      -
      7697  bool dedicatedAllocationExtensionEnabled,
      -
      7698  bool bindMemory2ExtensionEnabled,
      -
      7699  bool memoryBudgetExtensionEnabled,
      -
      7700  bool deviceCoherentMemoryExtensionEnabled);
      -
      7701  ~VmaRecorder();
      -
      7702 
      -
      7703  void RecordCreateAllocator(uint32_t frameIndex);
      -
      7704  void RecordDestroyAllocator(uint32_t frameIndex);
      -
      7705  void RecordCreatePool(uint32_t frameIndex,
      -
      7706  const VmaPoolCreateInfo& createInfo,
      -
      7707  VmaPool pool);
      -
      7708  void RecordDestroyPool(uint32_t frameIndex, VmaPool pool);
      -
      7709  void RecordAllocateMemory(uint32_t frameIndex,
      -
      7710  const VkMemoryRequirements& vkMemReq,
      -
      7711  const VmaAllocationCreateInfo& createInfo,
      -
      7712  VmaAllocation allocation);
      -
      7713  void RecordAllocateMemoryPages(uint32_t frameIndex,
      -
      7714  const VkMemoryRequirements& vkMemReq,
      -
      7715  const VmaAllocationCreateInfo& createInfo,
      -
      7716  uint64_t allocationCount,
      -
      7717  const VmaAllocation* pAllocations);
      -
      7718  void RecordAllocateMemoryForBuffer(uint32_t frameIndex,
      -
      7719  const VkMemoryRequirements& vkMemReq,
      -
      7720  bool requiresDedicatedAllocation,
      -
      7721  bool prefersDedicatedAllocation,
      -
      7722  const VmaAllocationCreateInfo& createInfo,
      -
      7723  VmaAllocation allocation);
      -
      7724  void RecordAllocateMemoryForImage(uint32_t frameIndex,
      -
      7725  const VkMemoryRequirements& vkMemReq,
      -
      7726  bool requiresDedicatedAllocation,
      -
      7727  bool prefersDedicatedAllocation,
      -
      7728  const VmaAllocationCreateInfo& createInfo,
      -
      7729  VmaAllocation allocation);
      -
      7730  void RecordFreeMemory(uint32_t frameIndex,
      -
      7731  VmaAllocation allocation);
      -
      7732  void RecordFreeMemoryPages(uint32_t frameIndex,
      -
      7733  uint64_t allocationCount,
      -
      7734  const VmaAllocation* pAllocations);
      -
      7735  void RecordSetAllocationUserData(uint32_t frameIndex,
      -
      7736  VmaAllocation allocation,
      -
      7737  const void* pUserData);
      -
      7738  void RecordCreateLostAllocation(uint32_t frameIndex,
      -
      7739  VmaAllocation allocation);
      -
      7740  void RecordMapMemory(uint32_t frameIndex,
      -
      7741  VmaAllocation allocation);
      -
      7742  void RecordUnmapMemory(uint32_t frameIndex,
      -
      7743  VmaAllocation allocation);
      -
      7744  void RecordFlushAllocation(uint32_t frameIndex,
      -
      7745  VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size);
      -
      7746  void RecordInvalidateAllocation(uint32_t frameIndex,
      -
      7747  VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size);
      -
      7748  void RecordCreateBuffer(uint32_t frameIndex,
      -
      7749  const VkBufferCreateInfo& bufCreateInfo,
      -
      7750  const VmaAllocationCreateInfo& allocCreateInfo,
      -
      7751  VmaAllocation allocation);
      -
      7752  void RecordCreateImage(uint32_t frameIndex,
      -
      7753  const VkImageCreateInfo& imageCreateInfo,
      -
      7754  const VmaAllocationCreateInfo& allocCreateInfo,
      -
      7755  VmaAllocation allocation);
      -
      7756  void RecordDestroyBuffer(uint32_t frameIndex,
      -
      7757  VmaAllocation allocation);
      -
      7758  void RecordDestroyImage(uint32_t frameIndex,
      -
      7759  VmaAllocation allocation);
      -
      7760  void RecordTouchAllocation(uint32_t frameIndex,
      -
      7761  VmaAllocation allocation);
      -
      7762  void RecordGetAllocationInfo(uint32_t frameIndex,
      -
      7763  VmaAllocation allocation);
      -
      7764  void RecordMakePoolAllocationsLost(uint32_t frameIndex,
      -
      7765  VmaPool pool);
      -
      7766  void RecordDefragmentationBegin(uint32_t frameIndex,
      -
      7767  const VmaDefragmentationInfo2& info,
      - -
      7769  void RecordDefragmentationEnd(uint32_t frameIndex,
      - -
      7771  void RecordSetPoolName(uint32_t frameIndex,
      -
      7772  VmaPool pool,
      -
      7773  const char* name);
      +
      7669  size_t CalcBlocksWithNonMovableCount() const;
      +
      7670 
      +
      7671  static bool MoveMakesSense(
      +
      7672  size_t dstBlockIndex, VkDeviceSize dstOffset,
      +
      7673  size_t srcBlockIndex, VkDeviceSize srcOffset);
      +
      7674 };
      +
      7675 
      +
      7676 class VmaDefragmentationAlgorithm_Fast : public VmaDefragmentationAlgorithm
      +
      7677 {
      +
      7678  VMA_CLASS_NO_COPY(VmaDefragmentationAlgorithm_Fast)
      +
      7679 public:
      +
      7680  VmaDefragmentationAlgorithm_Fast(
      +
      7681  VmaAllocator hAllocator,
      +
      7682  VmaBlockVector* pBlockVector,
      +
      7683  uint32_t currentFrameIndex,
      +
      7684  bool overlappingMoveSupported);
      +
      7685  virtual ~VmaDefragmentationAlgorithm_Fast();
      +
      7686 
      +
      7687  virtual void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged) { ++m_AllocationCount; }
      +
      7688  virtual void AddAll() { m_AllAllocations = true; }
      +
      7689 
      +
      7690  virtual VkResult Defragment(
      +
      7691  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
      +
      7692  VkDeviceSize maxBytesToMove,
      +
      7693  uint32_t maxAllocationsToMove,
      +
      7694  VmaDefragmentationFlags flags);
      +
      7695 
      +
      7696  virtual VkDeviceSize GetBytesMoved() const { return m_BytesMoved; }
      +
      7697  virtual uint32_t GetAllocationsMoved() const { return m_AllocationsMoved; }
      +
      7698 
      +
      7699 private:
      +
      7700  struct BlockInfo
      +
      7701  {
      +
      7702  size_t origBlockIndex;
      +
      7703  };
      +
      7704 
      +
      7705  class FreeSpaceDatabase
      +
      7706  {
      +
      7707  public:
      +
      7708  FreeSpaceDatabase()
      +
      7709  {
      +
      7710  FreeSpace s = {};
      +
      7711  s.blockInfoIndex = SIZE_MAX;
      +
      7712  for(size_t i = 0; i < MAX_COUNT; ++i)
      +
      7713  {
      +
      7714  m_FreeSpaces[i] = s;
      +
      7715  }
      +
      7716  }
      +
      7717 
      +
      7718  void Register(size_t blockInfoIndex, VkDeviceSize offset, VkDeviceSize size)
      +
      7719  {
      +
      7720  if(size < VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
      +
      7721  {
      +
      7722  return;
      +
      7723  }
      +
      7724 
      +
      7725  // Find first invalid or the smallest structure.
      +
      7726  size_t bestIndex = SIZE_MAX;
      +
      7727  for(size_t i = 0; i < MAX_COUNT; ++i)
      +
      7728  {
      +
      7729  // Empty structure.
      +
      7730  if(m_FreeSpaces[i].blockInfoIndex == SIZE_MAX)
      +
      7731  {
      +
      7732  bestIndex = i;
      +
      7733  break;
      +
      7734  }
      +
      7735  if(m_FreeSpaces[i].size < size &&
      +
      7736  (bestIndex == SIZE_MAX || m_FreeSpaces[bestIndex].size > m_FreeSpaces[i].size))
      +
      7737  {
      +
      7738  bestIndex = i;
      +
      7739  }
      +
      7740  }
      +
      7741 
      +
      7742  if(bestIndex != SIZE_MAX)
      +
      7743  {
      +
      7744  m_FreeSpaces[bestIndex].blockInfoIndex = blockInfoIndex;
      +
      7745  m_FreeSpaces[bestIndex].offset = offset;
      +
      7746  m_FreeSpaces[bestIndex].size = size;
      +
      7747  }
      +
      7748  }
      +
      7749 
      +
      7750  bool Fetch(VkDeviceSize alignment, VkDeviceSize size,
      +
      7751  size_t& outBlockInfoIndex, VkDeviceSize& outDstOffset)
      +
      7752  {
      +
      7753  size_t bestIndex = SIZE_MAX;
      +
      7754  VkDeviceSize bestFreeSpaceAfter = 0;
      +
      7755  for(size_t i = 0; i < MAX_COUNT; ++i)
      +
      7756  {
      +
      7757  // Structure is valid.
      +
      7758  if(m_FreeSpaces[i].blockInfoIndex != SIZE_MAX)
      +
      7759  {
      +
      7760  const VkDeviceSize dstOffset = VmaAlignUp(m_FreeSpaces[i].offset, alignment);
      +
      7761  // Allocation fits into this structure.
      +
      7762  if(dstOffset + size <= m_FreeSpaces[i].offset + m_FreeSpaces[i].size)
      +
      7763  {
      +
      7764  const VkDeviceSize freeSpaceAfter = (m_FreeSpaces[i].offset + m_FreeSpaces[i].size) -
      +
      7765  (dstOffset + size);
      +
      7766  if(bestIndex == SIZE_MAX || freeSpaceAfter > bestFreeSpaceAfter)
      +
      7767  {
      +
      7768  bestIndex = i;
      +
      7769  bestFreeSpaceAfter = freeSpaceAfter;
      +
      7770  }
      +
      7771  }
      +
      7772  }
      +
      7773  }
      7774 
      -
      7775 private:
      -
      7776  struct CallParams
      -
      7777  {
      -
      7778  uint32_t threadId;
      -
      7779  double time;
      -
      7780  };
      -
      7781 
      -
      7782  class UserDataString
      -
      7783  {
      -
      7784  public:
      -
      7785  UserDataString(VmaAllocationCreateFlags allocFlags, const void* pUserData);
      -
      7786  const char* GetString() const { return m_Str; }
      -
      7787 
      -
      7788  private:
      -
      7789  char m_PtrStr[17];
      -
      7790  const char* m_Str;
      -
      7791  };
      +
      7775  if(bestIndex != SIZE_MAX)
      +
      7776  {
      +
      7777  outBlockInfoIndex = m_FreeSpaces[bestIndex].blockInfoIndex;
      +
      7778  outDstOffset = VmaAlignUp(m_FreeSpaces[bestIndex].offset, alignment);
      +
      7779 
      +
      7780  if(bestFreeSpaceAfter >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
      +
      7781  {
      +
      7782  // Leave this structure for remaining empty space.
      +
      7783  const VkDeviceSize alignmentPlusSize = (outDstOffset - m_FreeSpaces[bestIndex].offset) + size;
      +
      7784  m_FreeSpaces[bestIndex].offset += alignmentPlusSize;
      +
      7785  m_FreeSpaces[bestIndex].size -= alignmentPlusSize;
      +
      7786  }
      +
      7787  else
      +
      7788  {
      +
      7789  // This structure becomes invalid.
      +
      7790  m_FreeSpaces[bestIndex].blockInfoIndex = SIZE_MAX;
      +
      7791  }
      7792 
      -
      7793  bool m_UseMutex;
      -
      7794  VmaRecordFlags m_Flags;
      -
      7795  FILE* m_File;
      -
      7796  VMA_MUTEX m_FileMutex;
      -
      7797  std::chrono::time_point<std::chrono::high_resolution_clock> m_RecordingStartTime;
      +
      7793  return true;
      +
      7794  }
      +
      7795 
      +
      7796  return false;
      +
      7797  }
      7798 
      -
      7799  void GetBasicParams(CallParams& outParams);
      -
      7800 
      -
      7801  // T must be a pointer type, e.g. VmaAllocation, VmaPool.
      -
      7802  template<typename T>
      -
      7803  void PrintPointerList(uint64_t count, const T* pItems)
      -
      7804  {
      -
      7805  if(count)
      -
      7806  {
      -
      7807  fprintf(m_File, "%p", pItems[0]);
      -
      7808  for(uint64_t i = 1; i < count; ++i)
      -
      7809  {
      -
      7810  fprintf(m_File, " %p", pItems[i]);
      -
      7811  }
      -
      7812  }
      -
      7813  }
      +
      7799  private:
      +
      7800  static const size_t MAX_COUNT = 4;
      +
      7801 
      +
      7802  struct FreeSpace
      +
      7803  {
      +
      7804  size_t blockInfoIndex; // SIZE_MAX means this structure is invalid.
      +
      7805  VkDeviceSize offset;
      +
      7806  VkDeviceSize size;
      +
      7807  } m_FreeSpaces[MAX_COUNT];
      +
      7808  };
      +
      7809 
      +
      7810  const bool m_OverlappingMoveSupported;
      +
      7811 
      +
      7812  uint32_t m_AllocationCount;
      +
      7813  bool m_AllAllocations;
      7814 
      -
      7815  void PrintPointerList(uint64_t count, const VmaAllocation* pItems);
      -
      7816  void Flush();
      -
      7817 };
      -
      7818 
      -
      7819 #endif // #if VMA_RECORDING_ENABLED
      -
      7820 
      -
      7821 /*
      -
      7822 Thread-safe wrapper over VmaPoolAllocator free list, for allocation of VmaAllocation_T objects.
      -
      7823 */
      -
      7824 class VmaAllocationObjectAllocator
      -
      7825 {
      -
      7826  VMA_CLASS_NO_COPY(VmaAllocationObjectAllocator)
      -
      7827 public:
      -
      7828  VmaAllocationObjectAllocator(const VkAllocationCallbacks* pAllocationCallbacks);
      -
      7829 
      -
      7830  template<typename... Types> VmaAllocation Allocate(Types... args);
      -
      7831  void Free(VmaAllocation hAlloc);
      -
      7832 
      -
      7833 private:
      -
      7834  VMA_MUTEX m_Mutex;
      -
      7835  VmaPoolAllocator<VmaAllocation_T> m_Allocator;
      -
      7836 };
      -
      7837 
      -
      7838 struct VmaCurrentBudgetData
      -
      7839 {
      -
      7840  VMA_ATOMIC_UINT64 m_BlockBytes[VK_MAX_MEMORY_HEAPS];
      -
      7841  VMA_ATOMIC_UINT64 m_AllocationBytes[VK_MAX_MEMORY_HEAPS];
      -
      7842 
      -
      7843 #if VMA_MEMORY_BUDGET
      -
      7844  VMA_ATOMIC_UINT32 m_OperationsSinceBudgetFetch;
      -
      7845  VMA_RW_MUTEX m_BudgetMutex;
      -
      7846  uint64_t m_VulkanUsage[VK_MAX_MEMORY_HEAPS];
      -
      7847  uint64_t m_VulkanBudget[VK_MAX_MEMORY_HEAPS];
      -
      7848  uint64_t m_BlockBytesAtBudgetFetch[VK_MAX_MEMORY_HEAPS];
      -
      7849 #endif // #if VMA_MEMORY_BUDGET
      -
      7850 
      -
      7851  VmaCurrentBudgetData()
      -
      7852  {
      -
      7853  for(uint32_t heapIndex = 0; heapIndex < VK_MAX_MEMORY_HEAPS; ++heapIndex)
      -
      7854  {
      -
      7855  m_BlockBytes[heapIndex] = 0;
      -
      7856  m_AllocationBytes[heapIndex] = 0;
      -
      7857 #if VMA_MEMORY_BUDGET
      -
      7858  m_VulkanUsage[heapIndex] = 0;
      -
      7859  m_VulkanBudget[heapIndex] = 0;
      -
      7860  m_BlockBytesAtBudgetFetch[heapIndex] = 0;
      -
      7861 #endif
      -
      7862  }
      -
      7863 
      -
      7864 #if VMA_MEMORY_BUDGET
      -
      7865  m_OperationsSinceBudgetFetch = 0;
      -
      7866 #endif
      -
      7867  }
      -
      7868 
      -
      7869  void AddAllocation(uint32_t heapIndex, VkDeviceSize allocationSize)
      -
      7870  {
      -
      7871  m_AllocationBytes[heapIndex] += allocationSize;
      -
      7872 #if VMA_MEMORY_BUDGET
      -
      7873  ++m_OperationsSinceBudgetFetch;
      -
      7874 #endif
      -
      7875  }
      -
      7876 
      -
      7877  void RemoveAllocation(uint32_t heapIndex, VkDeviceSize allocationSize)
      -
      7878  {
      -
      7879  VMA_ASSERT(m_AllocationBytes[heapIndex] >= allocationSize); // DELME
      -
      7880  m_AllocationBytes[heapIndex] -= allocationSize;
      -
      7881 #if VMA_MEMORY_BUDGET
      -
      7882  ++m_OperationsSinceBudgetFetch;
      -
      7883 #endif
      -
      7884  }
      -
      7885 };
      -
      7886 
      -
      7887 // Main allocator object.
      -
      7888 struct VmaAllocator_T
      -
      7889 {
      -
      7890  VMA_CLASS_NO_COPY(VmaAllocator_T)
      -
      7891 public:
      -
      7892  bool m_UseMutex;
      -
      7893  uint32_t m_VulkanApiVersion;
      -
      7894  bool m_UseKhrDedicatedAllocation; // Can be set only if m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0).
      -
      7895  bool m_UseKhrBindMemory2; // Can be set only if m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0).
      -
      7896  bool m_UseExtMemoryBudget;
      -
      7897  bool m_UseAmdDeviceCoherentMemory;
      -
      7898  bool m_UseKhrBufferDeviceAddress;
      -
      7899  bool m_UseExtMemoryPriority;
      -
      7900  VkDevice m_hDevice;
      -
      7901  VkInstance m_hInstance;
      -
      7902  bool m_AllocationCallbacksSpecified;
      -
      7903  VkAllocationCallbacks m_AllocationCallbacks;
      -
      7904  VmaDeviceMemoryCallbacks m_DeviceMemoryCallbacks;
      -
      7905  VmaAllocationObjectAllocator m_AllocationObjectAllocator;
      -
      7906 
      -
      7907  // Each bit (1 << i) is set if HeapSizeLimit is enabled for that heap, so cannot allocate more than the heap size.
      -
      7908  uint32_t m_HeapSizeLimitMask;
      -
      7909 
      -
      7910  VkPhysicalDeviceProperties m_PhysicalDeviceProperties;
      -
      7911  VkPhysicalDeviceMemoryProperties m_MemProps;
      -
      7912 
      -
      7913  // Default pools.
      -
      7914  VmaBlockVector* m_pBlockVectors[VK_MAX_MEMORY_TYPES];
      -
      7915 
      -
      7916  // Each vector is sorted by memory (handle value).
      -
      7917  typedef VmaVector< VmaAllocation, VmaStlAllocator<VmaAllocation> > AllocationVectorType;
      -
      7918  AllocationVectorType* m_pDedicatedAllocations[VK_MAX_MEMORY_TYPES];
      -
      7919  VMA_RW_MUTEX m_DedicatedAllocationsMutex[VK_MAX_MEMORY_TYPES];
      +
      7815  VkDeviceSize m_BytesMoved;
      +
      7816  uint32_t m_AllocationsMoved;
      +
      7817 
      +
      7818  VmaVector< BlockInfo, VmaStlAllocator<BlockInfo> > m_BlockInfos;
      +
      7819 
      +
      7820  void PreprocessMetadata();
      +
      7821  void PostprocessMetadata();
      +
      7822  void InsertSuballoc(VmaBlockMetadata_Generic* pMetadata, const VmaSuballocation& suballoc);
      +
      7823 };
      +
      7824 
      +
      7825 struct VmaBlockDefragmentationContext
      +
      7826 {
      +
      7827  enum BLOCK_FLAG
      +
      7828  {
      +
      7829  BLOCK_FLAG_USED = 0x00000001,
      +
      7830  };
      +
      7831  uint32_t flags;
      +
      7832  VkBuffer hBuffer;
      +
      7833 };
      +
      7834 
      +
      7835 class VmaBlockVectorDefragmentationContext
      +
      7836 {
      +
      7837  VMA_CLASS_NO_COPY(VmaBlockVectorDefragmentationContext)
      +
      7838 public:
      +
      7839  VkResult res;
      +
      7840  bool mutexLocked;
      +
      7841  VmaVector< VmaBlockDefragmentationContext, VmaStlAllocator<VmaBlockDefragmentationContext> > blockContexts;
      +
      7842  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> > defragmentationMoves;
      +
      7843  uint32_t defragmentationMovesProcessed;
      +
      7844  uint32_t defragmentationMovesCommitted;
      +
      7845  bool hasDefragmentationPlan;
      +
      7846 
      +
      7847  VmaBlockVectorDefragmentationContext(
      +
      7848  VmaAllocator hAllocator,
      +
      7849  VmaPool hCustomPool, // Optional.
      +
      7850  VmaBlockVector* pBlockVector,
      +
      7851  uint32_t currFrameIndex);
      +
      7852  ~VmaBlockVectorDefragmentationContext();
      +
      7853 
      +
      7854  VmaPool GetCustomPool() const { return m_hCustomPool; }
      +
      7855  VmaBlockVector* GetBlockVector() const { return m_pBlockVector; }
      +
      7856  VmaDefragmentationAlgorithm* GetAlgorithm() const { return m_pAlgorithm; }
      +
      7857 
      +
      7858  void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged);
      +
      7859  void AddAll() { m_AllAllocations = true; }
      +
      7860 
      +
      7861  void Begin(bool overlappingMoveSupported, VmaDefragmentationFlags flags);
      +
      7862 
      +
      7863 private:
      +
      7864  const VmaAllocator m_hAllocator;
      +
      7865  // Null if not from custom pool.
      +
      7866  const VmaPool m_hCustomPool;
      +
      7867  // Redundant, for convenience not to fetch from m_hCustomPool->m_BlockVector or m_hAllocator->m_pBlockVectors.
      +
      7868  VmaBlockVector* const m_pBlockVector;
      +
      7869  const uint32_t m_CurrFrameIndex;
      +
      7870  // Owner of this object.
      +
      7871  VmaDefragmentationAlgorithm* m_pAlgorithm;
      +
      7872 
      +
      7873  struct AllocInfo
      +
      7874  {
      +
      7875  VmaAllocation hAlloc;
      +
      7876  VkBool32* pChanged;
      +
      7877  };
      +
      7878  // Used between constructor and Begin.
      +
      7879  VmaVector< AllocInfo, VmaStlAllocator<AllocInfo> > m_Allocations;
      +
      7880  bool m_AllAllocations;
      +
      7881 };
      +
      7882 
      +
      7883 struct VmaDefragmentationContext_T
      +
      7884 {
      +
      7885 private:
      +
      7886  VMA_CLASS_NO_COPY(VmaDefragmentationContext_T)
      +
      7887 public:
      +
      7888  VmaDefragmentationContext_T(
      +
      7889  VmaAllocator hAllocator,
      +
      7890  uint32_t currFrameIndex,
      +
      7891  uint32_t flags,
      +
      7892  VmaDefragmentationStats* pStats);
      +
      7893  ~VmaDefragmentationContext_T();
      +
      7894 
      +
      7895  void AddPools(uint32_t poolCount, const VmaPool* pPools);
      +
      7896  void AddAllocations(
      +
      7897  uint32_t allocationCount,
      +
      7898  const VmaAllocation* pAllocations,
      +
      7899  VkBool32* pAllocationsChanged);
      +
      7900 
      +
      7901  /*
      +
      7902  Returns:
      +
      7903  - `VK_SUCCESS` if succeeded and object can be destroyed immediately.
      +
      7904  - `VK_NOT_READY` if succeeded but the object must remain alive until vmaDefragmentationEnd().
      +
      7905  - Negative value if error occured and object can be destroyed immediately.
      +
      7906  */
      +
      7907  VkResult Defragment(
      +
      7908  VkDeviceSize maxCpuBytesToMove, uint32_t maxCpuAllocationsToMove,
      +
      7909  VkDeviceSize maxGpuBytesToMove, uint32_t maxGpuAllocationsToMove,
      +
      7910  VkCommandBuffer commandBuffer, VmaDefragmentationStats* pStats, VmaDefragmentationFlags flags);
      +
      7911 
      +
      7912  VkResult DefragmentPassBegin(VmaDefragmentationPassInfo* pInfo);
      +
      7913  VkResult DefragmentPassEnd();
      +
      7914 
      +
      7915 private:
      +
      7916  const VmaAllocator m_hAllocator;
      +
      7917  const uint32_t m_CurrFrameIndex;
      +
      7918  const uint32_t m_Flags;
      +
      7919  VmaDefragmentationStats* const m_pStats;
      7920 
      -
      7921  VmaCurrentBudgetData m_Budget;
      -
      7922 
      -
      7923  VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo);
      -
      7924  VkResult Init(const VmaAllocatorCreateInfo* pCreateInfo);
      -
      7925  ~VmaAllocator_T();
      -
      7926 
      -
      7927  const VkAllocationCallbacks* GetAllocationCallbacks() const
      -
      7928  {
      -
      7929  return m_AllocationCallbacksSpecified ? &m_AllocationCallbacks : 0;
      -
      7930  }
      -
      7931  const VmaVulkanFunctions& GetVulkanFunctions() const
      -
      7932  {
      -
      7933  return m_VulkanFunctions;
      -
      7934  }
      -
      7935 
      -
      7936  VkPhysicalDevice GetPhysicalDevice() const { return m_PhysicalDevice; }
      -
      7937 
      -
      7938  VkDeviceSize GetBufferImageGranularity() const
      -
      7939  {
      -
      7940  return VMA_MAX(
      -
      7941  static_cast<VkDeviceSize>(VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY),
      -
      7942  m_PhysicalDeviceProperties.limits.bufferImageGranularity);
      -
      7943  }
      -
      7944 
      -
      7945  uint32_t GetMemoryHeapCount() const { return m_MemProps.memoryHeapCount; }
      -
      7946  uint32_t GetMemoryTypeCount() const { return m_MemProps.memoryTypeCount; }
      -
      7947 
      -
      7948  uint32_t MemoryTypeIndexToHeapIndex(uint32_t memTypeIndex) const
      -
      7949  {
      -
      7950  VMA_ASSERT(memTypeIndex < m_MemProps.memoryTypeCount);
      -
      7951  return m_MemProps.memoryTypes[memTypeIndex].heapIndex;
      -
      7952  }
      -
      7953  // True when specific memory type is HOST_VISIBLE but not HOST_COHERENT.
      -
      7954  bool IsMemoryTypeNonCoherent(uint32_t memTypeIndex) const
      -
      7955  {
      -
      7956  return (m_MemProps.memoryTypes[memTypeIndex].propertyFlags & (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) ==
      -
      7957  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
      -
      7958  }
      -
      7959  // Minimum alignment for all allocations in specific memory type.
      -
      7960  VkDeviceSize GetMemoryTypeMinAlignment(uint32_t memTypeIndex) const
      -
      7961  {
      -
      7962  return IsMemoryTypeNonCoherent(memTypeIndex) ?
      -
      7963  VMA_MAX((VkDeviceSize)VMA_DEBUG_ALIGNMENT, m_PhysicalDeviceProperties.limits.nonCoherentAtomSize) :
      -
      7964  (VkDeviceSize)VMA_DEBUG_ALIGNMENT;
      -
      7965  }
      -
      7966 
      -
      7967  bool IsIntegratedGpu() const
      -
      7968  {
      -
      7969  return m_PhysicalDeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
      -
      7970  }
      -
      7971 
      -
      7972  uint32_t GetGlobalMemoryTypeBits() const { return m_GlobalMemoryTypeBits; }
      -
      7973 
      -
      7974 #if VMA_RECORDING_ENABLED
      -
      7975  VmaRecorder* GetRecorder() const { return m_pRecorder; }
      -
      7976 #endif
      -
      7977 
      -
      7978  void GetBufferMemoryRequirements(
      -
      7979  VkBuffer hBuffer,
      -
      7980  VkMemoryRequirements& memReq,
      -
      7981  bool& requiresDedicatedAllocation,
      -
      7982  bool& prefersDedicatedAllocation) const;
      -
      7983  void GetImageMemoryRequirements(
      -
      7984  VkImage hImage,
      -
      7985  VkMemoryRequirements& memReq,
      -
      7986  bool& requiresDedicatedAllocation,
      -
      7987  bool& prefersDedicatedAllocation) const;
      -
      7988 
      -
      7989  // Main allocation function.
      -
      7990  VkResult AllocateMemory(
      -
      7991  const VkMemoryRequirements& vkMemReq,
      -
      7992  bool requiresDedicatedAllocation,
      -
      7993  bool prefersDedicatedAllocation,
      -
      7994  VkBuffer dedicatedBuffer,
      -
      7995  VkBufferUsageFlags dedicatedBufferUsage, // UINT32_MAX when unknown.
      -
      7996  VkImage dedicatedImage,
      -
      7997  const VmaAllocationCreateInfo& createInfo,
      -
      7998  VmaSuballocationType suballocType,
      -
      7999  size_t allocationCount,
      -
      8000  VmaAllocation* pAllocations);
      -
      8001 
      -
      8002  // Main deallocation function.
      -
      8003  void FreeMemory(
      -
      8004  size_t allocationCount,
      -
      8005  const VmaAllocation* pAllocations);
      -
      8006 
      -
      8007  VkResult ResizeAllocation(
      -
      8008  const VmaAllocation alloc,
      -
      8009  VkDeviceSize newSize);
      -
      8010 
      -
      8011  void CalculateStats(VmaStats* pStats);
      -
      8012 
      -
      8013  void GetBudget(
      -
      8014  VmaBudget* outBudget, uint32_t firstHeap, uint32_t heapCount);
      -
      8015 
      -
      8016 #if VMA_STATS_STRING_ENABLED
      -
      8017  void PrintDetailedMap(class VmaJsonWriter& json);
      -
      8018 #endif
      -
      8019 
      -
      8020  VkResult DefragmentationBegin(
      -
      8021  const VmaDefragmentationInfo2& info,
      -
      8022  VmaDefragmentationStats* pStats,
      -
      8023  VmaDefragmentationContext* pContext);
      -
      8024  VkResult DefragmentationEnd(
      -
      8025  VmaDefragmentationContext context);
      -
      8026 
      -
      8027  VkResult DefragmentationPassBegin(
      - -
      8029  VmaDefragmentationContext context);
      -
      8030  VkResult DefragmentationPassEnd(
      -
      8031  VmaDefragmentationContext context);
      -
      8032 
      -
      8033  void GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo);
      -
      8034  bool TouchAllocation(VmaAllocation hAllocation);
      -
      8035 
      -
      8036  VkResult CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPool* pPool);
      -
      8037  void DestroyPool(VmaPool pool);
      -
      8038  void GetPoolStats(VmaPool pool, VmaPoolStats* pPoolStats);
      -
      8039 
      -
      8040  void SetCurrentFrameIndex(uint32_t frameIndex);
      -
      8041  uint32_t GetCurrentFrameIndex() const { return m_CurrentFrameIndex.load(); }
      -
      8042 
      -
      8043  void MakePoolAllocationsLost(
      -
      8044  VmaPool hPool,
      -
      8045  size_t* pLostAllocationCount);
      -
      8046  VkResult CheckPoolCorruption(VmaPool hPool);
      -
      8047  VkResult CheckCorruption(uint32_t memoryTypeBits);
      -
      8048 
      -
      8049  void CreateLostAllocation(VmaAllocation* pAllocation);
      -
      8050 
      -
      8051  // Call to Vulkan function vkAllocateMemory with accompanying bookkeeping.
      -
      8052  VkResult AllocateVulkanMemory(const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory);
      -
      8053  // Call to Vulkan function vkFreeMemory with accompanying bookkeeping.
      -
      8054  void FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, VkDeviceMemory hMemory);
      -
      8055  // Call to Vulkan function vkBindBufferMemory or vkBindBufferMemory2KHR.
      -
      8056  VkResult BindVulkanBuffer(
      -
      8057  VkDeviceMemory memory,
      -
      8058  VkDeviceSize memoryOffset,
      -
      8059  VkBuffer buffer,
      -
      8060  const void* pNext);
      -
      8061  // Call to Vulkan function vkBindImageMemory or vkBindImageMemory2KHR.
      -
      8062  VkResult BindVulkanImage(
      -
      8063  VkDeviceMemory memory,
      -
      8064  VkDeviceSize memoryOffset,
      -
      8065  VkImage image,
      -
      8066  const void* pNext);
      -
      8067 
      -
      8068  VkResult Map(VmaAllocation hAllocation, void** ppData);
      -
      8069  void Unmap(VmaAllocation hAllocation);
      -
      8070 
      -
      8071  VkResult BindBufferMemory(
      -
      8072  VmaAllocation hAllocation,
      -
      8073  VkDeviceSize allocationLocalOffset,
      -
      8074  VkBuffer hBuffer,
      -
      8075  const void* pNext);
      -
      8076  VkResult BindImageMemory(
      -
      8077  VmaAllocation hAllocation,
      -
      8078  VkDeviceSize allocationLocalOffset,
      -
      8079  VkImage hImage,
      -
      8080  const void* pNext);
      -
      8081 
      -
      8082  VkResult FlushOrInvalidateAllocation(
      -
      8083  VmaAllocation hAllocation,
      -
      8084  VkDeviceSize offset, VkDeviceSize size,
      -
      8085  VMA_CACHE_OPERATION op);
      -
      8086  VkResult FlushOrInvalidateAllocations(
      -
      8087  uint32_t allocationCount,
      -
      8088  const VmaAllocation* allocations,
      -
      8089  const VkDeviceSize* offsets, const VkDeviceSize* sizes,
      -
      8090  VMA_CACHE_OPERATION op);
      -
      8091 
      -
      8092  void FillAllocation(const VmaAllocation hAllocation, uint8_t pattern);
      -
      8093 
      -
      8094  /*
      -
      8095  Returns bit mask of memory types that can support defragmentation on GPU as
      -
      8096  they support creation of required buffer for copy operations.
      -
      8097  */
      -
      8098  uint32_t GetGpuDefragmentationMemoryTypeBits();
      -
      8099 
      -
      8100 private:
      -
      8101  VkDeviceSize m_PreferredLargeHeapBlockSize;
      -
      8102 
      -
      8103  VkPhysicalDevice m_PhysicalDevice;
      -
      8104  VMA_ATOMIC_UINT32 m_CurrentFrameIndex;
      -
      8105  VMA_ATOMIC_UINT32 m_GpuDefragmentationMemoryTypeBits; // UINT32_MAX means uninitialized.
      -
      8106 
      -
      8107  VMA_RW_MUTEX m_PoolsMutex;
      -
      8108  // Protected by m_PoolsMutex. Sorted by pointer value.
      -
      8109  VmaVector<VmaPool, VmaStlAllocator<VmaPool> > m_Pools;
      -
      8110  uint32_t m_NextPoolId;
      -
      8111 
      -
      8112  VmaVulkanFunctions m_VulkanFunctions;
      -
      8113 
      -
      8114  // Global bit mask AND-ed with any memoryTypeBits to disallow certain memory types.
      -
      8115  uint32_t m_GlobalMemoryTypeBits;
      -
      8116 
      -
      8117 #if VMA_RECORDING_ENABLED
      -
      8118  VmaRecorder* m_pRecorder;
      -
      8119 #endif
      -
      8120 
      -
      8121  void ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunctions);
      +
      7921  VkDeviceSize m_MaxCpuBytesToMove;
      +
      7922  uint32_t m_MaxCpuAllocationsToMove;
      +
      7923  VkDeviceSize m_MaxGpuBytesToMove;
      +
      7924  uint32_t m_MaxGpuAllocationsToMove;
      +
      7925 
      +
      7926  // Owner of these objects.
      +
      7927  VmaBlockVectorDefragmentationContext* m_DefaultPoolContexts[VK_MAX_MEMORY_TYPES];
      +
      7928  // Owner of these objects.
      +
      7929  VmaVector< VmaBlockVectorDefragmentationContext*, VmaStlAllocator<VmaBlockVectorDefragmentationContext*> > m_CustomPoolContexts;
      +
      7930 };
      +
      7931 
      +
      7932 #if VMA_RECORDING_ENABLED
      +
      7933 
      +
      7934 class VmaRecorder
      +
      7935 {
      +
      7936 public:
      +
      7937  VmaRecorder();
      +
      7938  VkResult Init(const VmaRecordSettings& settings, bool useMutex);
      +
      7939  void WriteConfiguration(
      +
      7940  const VkPhysicalDeviceProperties& devProps,
      +
      7941  const VkPhysicalDeviceMemoryProperties& memProps,
      +
      7942  uint32_t vulkanApiVersion,
      +
      7943  bool dedicatedAllocationExtensionEnabled,
      +
      7944  bool bindMemory2ExtensionEnabled,
      +
      7945  bool memoryBudgetExtensionEnabled,
      +
      7946  bool deviceCoherentMemoryExtensionEnabled);
      +
      7947  ~VmaRecorder();
      +
      7948 
      +
      7949  void RecordCreateAllocator(uint32_t frameIndex);
      +
      7950  void RecordDestroyAllocator(uint32_t frameIndex);
      +
      7951  void RecordCreatePool(uint32_t frameIndex,
      +
      7952  const VmaPoolCreateInfo& createInfo,
      +
      7953  VmaPool pool);
      +
      7954  void RecordDestroyPool(uint32_t frameIndex, VmaPool pool);
      +
      7955  void RecordAllocateMemory(uint32_t frameIndex,
      +
      7956  const VkMemoryRequirements& vkMemReq,
      +
      7957  const VmaAllocationCreateInfo& createInfo,
      +
      7958  VmaAllocation allocation);
      +
      7959  void RecordAllocateMemoryPages(uint32_t frameIndex,
      +
      7960  const VkMemoryRequirements& vkMemReq,
      +
      7961  const VmaAllocationCreateInfo& createInfo,
      +
      7962  uint64_t allocationCount,
      +
      7963  const VmaAllocation* pAllocations);
      +
      7964  void RecordAllocateMemoryForBuffer(uint32_t frameIndex,
      +
      7965  const VkMemoryRequirements& vkMemReq,
      +
      7966  bool requiresDedicatedAllocation,
      +
      7967  bool prefersDedicatedAllocation,
      +
      7968  const VmaAllocationCreateInfo& createInfo,
      +
      7969  VmaAllocation allocation);
      +
      7970  void RecordAllocateMemoryForImage(uint32_t frameIndex,
      +
      7971  const VkMemoryRequirements& vkMemReq,
      +
      7972  bool requiresDedicatedAllocation,
      +
      7973  bool prefersDedicatedAllocation,
      +
      7974  const VmaAllocationCreateInfo& createInfo,
      +
      7975  VmaAllocation allocation);
      +
      7976  void RecordFreeMemory(uint32_t frameIndex,
      +
      7977  VmaAllocation allocation);
      +
      7978  void RecordFreeMemoryPages(uint32_t frameIndex,
      +
      7979  uint64_t allocationCount,
      +
      7980  const VmaAllocation* pAllocations);
      +
      7981  void RecordSetAllocationUserData(uint32_t frameIndex,
      +
      7982  VmaAllocation allocation,
      +
      7983  const void* pUserData);
      +
      7984  void RecordCreateLostAllocation(uint32_t frameIndex,
      +
      7985  VmaAllocation allocation);
      +
      7986  void RecordMapMemory(uint32_t frameIndex,
      +
      7987  VmaAllocation allocation);
      +
      7988  void RecordUnmapMemory(uint32_t frameIndex,
      +
      7989  VmaAllocation allocation);
      +
      7990  void RecordFlushAllocation(uint32_t frameIndex,
      +
      7991  VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size);
      +
      7992  void RecordInvalidateAllocation(uint32_t frameIndex,
      +
      7993  VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size);
      +
      7994  void RecordCreateBuffer(uint32_t frameIndex,
      +
      7995  const VkBufferCreateInfo& bufCreateInfo,
      +
      7996  const VmaAllocationCreateInfo& allocCreateInfo,
      +
      7997  VmaAllocation allocation);
      +
      7998  void RecordCreateImage(uint32_t frameIndex,
      +
      7999  const VkImageCreateInfo& imageCreateInfo,
      +
      8000  const VmaAllocationCreateInfo& allocCreateInfo,
      +
      8001  VmaAllocation allocation);
      +
      8002  void RecordDestroyBuffer(uint32_t frameIndex,
      +
      8003  VmaAllocation allocation);
      +
      8004  void RecordDestroyImage(uint32_t frameIndex,
      +
      8005  VmaAllocation allocation);
      +
      8006  void RecordTouchAllocation(uint32_t frameIndex,
      +
      8007  VmaAllocation allocation);
      +
      8008  void RecordGetAllocationInfo(uint32_t frameIndex,
      +
      8009  VmaAllocation allocation);
      +
      8010  void RecordMakePoolAllocationsLost(uint32_t frameIndex,
      +
      8011  VmaPool pool);
      +
      8012  void RecordDefragmentationBegin(uint32_t frameIndex,
      +
      8013  const VmaDefragmentationInfo2& info,
      + +
      8015  void RecordDefragmentationEnd(uint32_t frameIndex,
      + +
      8017  void RecordSetPoolName(uint32_t frameIndex,
      +
      8018  VmaPool pool,
      +
      8019  const char* name);
      +
      8020 
      +
      8021 private:
      +
      8022  struct CallParams
      +
      8023  {
      +
      8024  uint32_t threadId;
      +
      8025  double time;
      +
      8026  };
      +
      8027 
      +
      8028  class UserDataString
      +
      8029  {
      +
      8030  public:
      +
      8031  UserDataString(VmaAllocationCreateFlags allocFlags, const void* pUserData);
      +
      8032  const char* GetString() const { return m_Str; }
      +
      8033 
      +
      8034  private:
      +
      8035  char m_PtrStr[17];
      +
      8036  const char* m_Str;
      +
      8037  };
      +
      8038 
      +
      8039  bool m_UseMutex;
      +
      8040  VmaRecordFlags m_Flags;
      +
      8041  FILE* m_File;
      +
      8042  VMA_MUTEX m_FileMutex;
      +
      8043  std::chrono::time_point<std::chrono::high_resolution_clock> m_RecordingStartTime;
      +
      8044 
      +
      8045  void GetBasicParams(CallParams& outParams);
      +
      8046 
      +
      8047  // T must be a pointer type, e.g. VmaAllocation, VmaPool.
      +
      8048  template<typename T>
      +
      8049  void PrintPointerList(uint64_t count, const T* pItems)
      +
      8050  {
      +
      8051  if(count)
      +
      8052  {
      +
      8053  fprintf(m_File, "%p", pItems[0]);
      +
      8054  for(uint64_t i = 1; i < count; ++i)
      +
      8055  {
      +
      8056  fprintf(m_File, " %p", pItems[i]);
      +
      8057  }
      +
      8058  }
      +
      8059  }
      +
      8060 
      +
      8061  void PrintPointerList(uint64_t count, const VmaAllocation* pItems);
      +
      8062  void Flush();
      +
      8063 };
      +
      8064 
      +
      8065 #endif // #if VMA_RECORDING_ENABLED
      +
      8066 
      +
      8067 /*
      +
      8068 Thread-safe wrapper over VmaPoolAllocator free list, for allocation of VmaAllocation_T objects.
      +
      8069 */
      +
      8070 class VmaAllocationObjectAllocator
      +
      8071 {
      +
      8072  VMA_CLASS_NO_COPY(VmaAllocationObjectAllocator)
      +
      8073 public:
      +
      8074  VmaAllocationObjectAllocator(const VkAllocationCallbacks* pAllocationCallbacks);
      +
      8075 
      +
      8076  template<typename... Types> VmaAllocation Allocate(Types... args);
      +
      8077  void Free(VmaAllocation hAlloc);
      +
      8078 
      +
      8079 private:
      +
      8080  VMA_MUTEX m_Mutex;
      +
      8081  VmaPoolAllocator<VmaAllocation_T> m_Allocator;
      +
      8082 };
      +
      8083 
      +
      8084 struct VmaCurrentBudgetData
      +
      8085 {
      +
      8086  VMA_ATOMIC_UINT64 m_BlockBytes[VK_MAX_MEMORY_HEAPS];
      +
      8087  VMA_ATOMIC_UINT64 m_AllocationBytes[VK_MAX_MEMORY_HEAPS];
      +
      8088 
      +
      8089 #if VMA_MEMORY_BUDGET
      +
      8090  VMA_ATOMIC_UINT32 m_OperationsSinceBudgetFetch;
      +
      8091  VMA_RW_MUTEX m_BudgetMutex;
      +
      8092  uint64_t m_VulkanUsage[VK_MAX_MEMORY_HEAPS];
      +
      8093  uint64_t m_VulkanBudget[VK_MAX_MEMORY_HEAPS];
      +
      8094  uint64_t m_BlockBytesAtBudgetFetch[VK_MAX_MEMORY_HEAPS];
      +
      8095 #endif // #if VMA_MEMORY_BUDGET
      +
      8096 
      +
      8097  VmaCurrentBudgetData()
      +
      8098  {
      +
      8099  for(uint32_t heapIndex = 0; heapIndex < VK_MAX_MEMORY_HEAPS; ++heapIndex)
      +
      8100  {
      +
      8101  m_BlockBytes[heapIndex] = 0;
      +
      8102  m_AllocationBytes[heapIndex] = 0;
      +
      8103 #if VMA_MEMORY_BUDGET
      +
      8104  m_VulkanUsage[heapIndex] = 0;
      +
      8105  m_VulkanBudget[heapIndex] = 0;
      +
      8106  m_BlockBytesAtBudgetFetch[heapIndex] = 0;
      +
      8107 #endif
      +
      8108  }
      +
      8109 
      +
      8110 #if VMA_MEMORY_BUDGET
      +
      8111  m_OperationsSinceBudgetFetch = 0;
      +
      8112 #endif
      +
      8113  }
      +
      8114 
      +
      8115  void AddAllocation(uint32_t heapIndex, VkDeviceSize allocationSize)
      +
      8116  {
      +
      8117  m_AllocationBytes[heapIndex] += allocationSize;
      +
      8118 #if VMA_MEMORY_BUDGET
      +
      8119  ++m_OperationsSinceBudgetFetch;
      +
      8120 #endif
      +
      8121  }
      8122 
      -
      8123 #if VMA_STATIC_VULKAN_FUNCTIONS == 1
      -
      8124  void ImportVulkanFunctions_Static();
      -
      8125 #endif
      -
      8126 
      -
      8127  void ImportVulkanFunctions_Custom(const VmaVulkanFunctions* pVulkanFunctions);
      -
      8128 
      -
      8129 #if VMA_DYNAMIC_VULKAN_FUNCTIONS == 1
      -
      8130  void ImportVulkanFunctions_Dynamic();
      -
      8131 #endif
      +
      8123  void RemoveAllocation(uint32_t heapIndex, VkDeviceSize allocationSize)
      +
      8124  {
      +
      8125  VMA_ASSERT(m_AllocationBytes[heapIndex] >= allocationSize); // DELME
      +
      8126  m_AllocationBytes[heapIndex] -= allocationSize;
      +
      8127 #if VMA_MEMORY_BUDGET
      +
      8128  ++m_OperationsSinceBudgetFetch;
      +
      8129 #endif
      +
      8130  }
      +
      8131 };
      8132 
      -
      8133  void ValidateVulkanFunctions();
      -
      8134 
      -
      8135  VkDeviceSize CalcPreferredBlockSize(uint32_t memTypeIndex);
      -
      8136 
      -
      8137  VkResult AllocateMemoryOfType(
      -
      8138  VkDeviceSize size,
      -
      8139  VkDeviceSize alignment,
      -
      8140  bool dedicatedAllocation,
      -
      8141  VkBuffer dedicatedBuffer,
      -
      8142  VkBufferUsageFlags dedicatedBufferUsage,
      -
      8143  VkImage dedicatedImage,
      -
      8144  const VmaAllocationCreateInfo& createInfo,
      -
      8145  uint32_t memTypeIndex,
      -
      8146  VmaSuballocationType suballocType,
      -
      8147  size_t allocationCount,
      -
      8148  VmaAllocation* pAllocations);
      -
      8149 
      -
      8150  // Helper function only to be used inside AllocateDedicatedMemory.
      -
      8151  VkResult AllocateDedicatedMemoryPage(
      -
      8152  VkDeviceSize size,
      -
      8153  VmaSuballocationType suballocType,
      -
      8154  uint32_t memTypeIndex,
      -
      8155  const VkMemoryAllocateInfo& allocInfo,
      -
      8156  bool map,
      -
      8157  bool isUserDataString,
      -
      8158  void* pUserData,
      -
      8159  VmaAllocation* pAllocation);
      -
      8160 
      -
      8161  // Allocates and registers new VkDeviceMemory specifically for dedicated allocations.
      -
      8162  VkResult AllocateDedicatedMemory(
      -
      8163  VkDeviceSize size,
      -
      8164  VmaSuballocationType suballocType,
      -
      8165  uint32_t memTypeIndex,
      -
      8166  bool withinBudget,
      -
      8167  bool map,
      -
      8168  bool isUserDataString,
      -
      8169  void* pUserData,
      -
      8170  float priority,
      -
      8171  VkBuffer dedicatedBuffer,
      -
      8172  VkBufferUsageFlags dedicatedBufferUsage,
      -
      8173  VkImage dedicatedImage,
      -
      8174  size_t allocationCount,
      -
      8175  VmaAllocation* pAllocations);
      -
      8176 
      -
      8177  void FreeDedicatedMemory(const VmaAllocation allocation);
      -
      8178 
      -
      8179  /*
      -
      8180  Calculates and returns bit mask of memory types that can support defragmentation
      -
      8181  on GPU as they support creation of required buffer for copy operations.
      -
      8182  */
      -
      8183  uint32_t CalculateGpuDefragmentationMemoryTypeBits() const;
      -
      8184 
      -
      8185  uint32_t CalculateGlobalMemoryTypeBits() const;
      -
      8186 
      -
      8187  bool GetFlushOrInvalidateRange(
      -
      8188  VmaAllocation allocation,
      -
      8189  VkDeviceSize offset, VkDeviceSize size,
      -
      8190  VkMappedMemoryRange& outRange) const;
      -
      8191 
      -
      8192 #if VMA_MEMORY_BUDGET
      -
      8193  void UpdateVulkanBudget();
      -
      8194 #endif // #if VMA_MEMORY_BUDGET
      -
      8195 };
      -
      8196 
      -
      8198 // Memory allocation #2 after VmaAllocator_T definition
      -
      8199 
      -
      8200 static void* VmaMalloc(VmaAllocator hAllocator, size_t size, size_t alignment)
      -
      8201 {
      -
      8202  return VmaMalloc(&hAllocator->m_AllocationCallbacks, size, alignment);
      -
      8203 }
      -
      8204 
      -
      8205 static void VmaFree(VmaAllocator hAllocator, void* ptr)
      -
      8206 {
      -
      8207  VmaFree(&hAllocator->m_AllocationCallbacks, ptr);
      -
      8208 }
      -
      8209 
      -
      8210 template<typename T>
      -
      8211 static T* VmaAllocate(VmaAllocator hAllocator)
      -
      8212 {
      -
      8213  return (T*)VmaMalloc(hAllocator, sizeof(T), VMA_ALIGN_OF(T));
      -
      8214 }
      -
      8215 
      -
      8216 template<typename T>
      -
      8217 static T* VmaAllocateArray(VmaAllocator hAllocator, size_t count)
      -
      8218 {
      -
      8219  return (T*)VmaMalloc(hAllocator, sizeof(T) * count, VMA_ALIGN_OF(T));
      -
      8220 }
      -
      8221 
      -
      8222 template<typename T>
      -
      8223 static void vma_delete(VmaAllocator hAllocator, T* ptr)
      -
      8224 {
      -
      8225  if(ptr != VMA_NULL)
      -
      8226  {
      -
      8227  ptr->~T();
      -
      8228  VmaFree(hAllocator, ptr);
      -
      8229  }
      -
      8230 }
      -
      8231 
      -
      8232 template<typename T>
      -
      8233 static void vma_delete_array(VmaAllocator hAllocator, T* ptr, size_t count)
      -
      8234 {
      -
      8235  if(ptr != VMA_NULL)
      -
      8236  {
      -
      8237  for(size_t i = count; i--; )
      -
      8238  ptr[i].~T();
      -
      8239  VmaFree(hAllocator, ptr);
      -
      8240  }
      -
      8241 }
      -
      8242 
      -
      8244 // VmaStringBuilder
      -
      8245 
      -
      8246 #if VMA_STATS_STRING_ENABLED
      +
      8133 // Main allocator object.
      +
      8134 struct VmaAllocator_T
      +
      8135 {
      +
      8136  VMA_CLASS_NO_COPY(VmaAllocator_T)
      +
      8137 public:
      +
      8138  bool m_UseMutex;
      +
      8139  uint32_t m_VulkanApiVersion;
      +
      8140  bool m_UseKhrDedicatedAllocation; // Can be set only if m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0).
      +
      8141  bool m_UseKhrBindMemory2; // Can be set only if m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0).
      +
      8142  bool m_UseExtMemoryBudget;
      +
      8143  bool m_UseAmdDeviceCoherentMemory;
      +
      8144  bool m_UseKhrBufferDeviceAddress;
      +
      8145  bool m_UseExtMemoryPriority;
      +
      8146  VkDevice m_hDevice;
      +
      8147  VkInstance m_hInstance;
      +
      8148  bool m_AllocationCallbacksSpecified;
      +
      8149  VkAllocationCallbacks m_AllocationCallbacks;
      +
      8150  VmaDeviceMemoryCallbacks m_DeviceMemoryCallbacks;
      +
      8151  VmaAllocationObjectAllocator m_AllocationObjectAllocator;
      +
      8152 
      +
      8153  // Each bit (1 << i) is set if HeapSizeLimit is enabled for that heap, so cannot allocate more than the heap size.
      +
      8154  uint32_t m_HeapSizeLimitMask;
      +
      8155 
      +
      8156  VkPhysicalDeviceProperties m_PhysicalDeviceProperties;
      +
      8157  VkPhysicalDeviceMemoryProperties m_MemProps;
      +
      8158 
      +
      8159  // Default pools.
      +
      8160  VmaBlockVector* m_pBlockVectors[VK_MAX_MEMORY_TYPES];
      +
      8161 
      +
      8162  typedef VmaIntrusiveLinkedList<VmaDedicatedAllocationListItemTraits> DedicatedAllocationLinkedList;
      +
      8163  DedicatedAllocationLinkedList m_DedicatedAllocations[VK_MAX_MEMORY_TYPES];
      +
      8164  VMA_RW_MUTEX m_DedicatedAllocationsMutex[VK_MAX_MEMORY_TYPES];
      +
      8165 
      +
      8166  VmaCurrentBudgetData m_Budget;
      +
      8167  VMA_ATOMIC_UINT32 m_DeviceMemoryCount; // Total number of VkDeviceMemory objects.
      +
      8168 
      +
      8169  VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo);
      +
      8170  VkResult Init(const VmaAllocatorCreateInfo* pCreateInfo);
      +
      8171  ~VmaAllocator_T();
      +
      8172 
      +
      8173  const VkAllocationCallbacks* GetAllocationCallbacks() const
      +
      8174  {
      +
      8175  return m_AllocationCallbacksSpecified ? &m_AllocationCallbacks : 0;
      +
      8176  }
      +
      8177  const VmaVulkanFunctions& GetVulkanFunctions() const
      +
      8178  {
      +
      8179  return m_VulkanFunctions;
      +
      8180  }
      +
      8181 
      +
      8182  VkPhysicalDevice GetPhysicalDevice() const { return m_PhysicalDevice; }
      +
      8183 
      +
      8184  VkDeviceSize GetBufferImageGranularity() const
      +
      8185  {
      +
      8186  return VMA_MAX(
      +
      8187  static_cast<VkDeviceSize>(VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY),
      +
      8188  m_PhysicalDeviceProperties.limits.bufferImageGranularity);
      +
      8189  }
      +
      8190 
      +
      8191  uint32_t GetMemoryHeapCount() const { return m_MemProps.memoryHeapCount; }
      +
      8192  uint32_t GetMemoryTypeCount() const { return m_MemProps.memoryTypeCount; }
      +
      8193 
      +
      8194  uint32_t MemoryTypeIndexToHeapIndex(uint32_t memTypeIndex) const
      +
      8195  {
      +
      8196  VMA_ASSERT(memTypeIndex < m_MemProps.memoryTypeCount);
      +
      8197  return m_MemProps.memoryTypes[memTypeIndex].heapIndex;
      +
      8198  }
      +
      8199  // True when specific memory type is HOST_VISIBLE but not HOST_COHERENT.
      +
      8200  bool IsMemoryTypeNonCoherent(uint32_t memTypeIndex) const
      +
      8201  {
      +
      8202  return (m_MemProps.memoryTypes[memTypeIndex].propertyFlags & (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) ==
      +
      8203  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
      +
      8204  }
      +
      8205  // Minimum alignment for all allocations in specific memory type.
      +
      8206  VkDeviceSize GetMemoryTypeMinAlignment(uint32_t memTypeIndex) const
      +
      8207  {
      +
      8208  return IsMemoryTypeNonCoherent(memTypeIndex) ?
      +
      8209  VMA_MAX((VkDeviceSize)VMA_DEBUG_ALIGNMENT, m_PhysicalDeviceProperties.limits.nonCoherentAtomSize) :
      +
      8210  (VkDeviceSize)VMA_DEBUG_ALIGNMENT;
      +
      8211  }
      +
      8212 
      +
      8213  bool IsIntegratedGpu() const
      +
      8214  {
      +
      8215  return m_PhysicalDeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
      +
      8216  }
      +
      8217 
      +
      8218  uint32_t GetGlobalMemoryTypeBits() const { return m_GlobalMemoryTypeBits; }
      +
      8219 
      +
      8220 #if VMA_RECORDING_ENABLED
      +
      8221  VmaRecorder* GetRecorder() const { return m_pRecorder; }
      +
      8222 #endif
      +
      8223 
      +
      8224  void GetBufferMemoryRequirements(
      +
      8225  VkBuffer hBuffer,
      +
      8226  VkMemoryRequirements& memReq,
      +
      8227  bool& requiresDedicatedAllocation,
      +
      8228  bool& prefersDedicatedAllocation) const;
      +
      8229  void GetImageMemoryRequirements(
      +
      8230  VkImage hImage,
      +
      8231  VkMemoryRequirements& memReq,
      +
      8232  bool& requiresDedicatedAllocation,
      +
      8233  bool& prefersDedicatedAllocation) const;
      +
      8234 
      +
      8235  // Main allocation function.
      +
      8236  VkResult AllocateMemory(
      +
      8237  const VkMemoryRequirements& vkMemReq,
      +
      8238  bool requiresDedicatedAllocation,
      +
      8239  bool prefersDedicatedAllocation,
      +
      8240  VkBuffer dedicatedBuffer,
      +
      8241  VkBufferUsageFlags dedicatedBufferUsage, // UINT32_MAX when unknown.
      +
      8242  VkImage dedicatedImage,
      +
      8243  const VmaAllocationCreateInfo& createInfo,
      +
      8244  VmaSuballocationType suballocType,
      +
      8245  size_t allocationCount,
      +
      8246  VmaAllocation* pAllocations);
      8247 
      -
      8248 class VmaStringBuilder
      -
      8249 {
      -
      8250 public:
      -
      8251  VmaStringBuilder(VmaAllocator alloc) : m_Data(VmaStlAllocator<char>(alloc->GetAllocationCallbacks())) { }
      -
      8252  size_t GetLength() const { return m_Data.size(); }
      -
      8253  const char* GetData() const { return m_Data.data(); }
      +
      8248  // Main deallocation function.
      +
      8249  void FreeMemory(
      +
      8250  size_t allocationCount,
      +
      8251  const VmaAllocation* pAllocations);
      +
      8252 
      +
      8253  void CalculateStats(VmaStats* pStats);
      8254 
      -
      8255  void Add(char ch) { m_Data.push_back(ch); }
      -
      8256  void Add(const char* pStr);
      -
      8257  void AddNewLine() { Add('\n'); }
      -
      8258  void AddNumber(uint32_t num);
      -
      8259  void AddNumber(uint64_t num);
      -
      8260  void AddPointer(const void* ptr);
      +
      8255  void GetBudget(
      +
      8256  VmaBudget* outBudget, uint32_t firstHeap, uint32_t heapCount);
      +
      8257 
      +
      8258 #if VMA_STATS_STRING_ENABLED
      +
      8259  void PrintDetailedMap(class VmaJsonWriter& json);
      +
      8260 #endif
      8261 
      -
      8262 private:
      -
      8263  VmaVector< char, VmaStlAllocator<char> > m_Data;
      -
      8264 };
      -
      8265 
      -
      8266 void VmaStringBuilder::Add(const char* pStr)
      -
      8267 {
      -
      8268  const size_t strLen = strlen(pStr);
      -
      8269  if(strLen > 0)
      -
      8270  {
      -
      8271  const size_t oldCount = m_Data.size();
      -
      8272  m_Data.resize(oldCount + strLen);
      -
      8273  memcpy(m_Data.data() + oldCount, pStr, strLen);
      -
      8274  }
      -
      8275 }
      -
      8276 
      -
      8277 void VmaStringBuilder::AddNumber(uint32_t num)
      -
      8278 {
      -
      8279  char buf[11];
      -
      8280  buf[10] = '\0';
      -
      8281  char *p = &buf[10];
      -
      8282  do
      -
      8283  {
      -
      8284  *--p = '0' + (num % 10);
      -
      8285  num /= 10;
      -
      8286  }
      -
      8287  while(num);
      -
      8288  Add(p);
      -
      8289 }
      +
      8262  VkResult DefragmentationBegin(
      +
      8263  const VmaDefragmentationInfo2& info,
      +
      8264  VmaDefragmentationStats* pStats,
      +
      8265  VmaDefragmentationContext* pContext);
      +
      8266  VkResult DefragmentationEnd(
      +
      8267  VmaDefragmentationContext context);
      +
      8268 
      +
      8269  VkResult DefragmentationPassBegin(
      + +
      8271  VmaDefragmentationContext context);
      +
      8272  VkResult DefragmentationPassEnd(
      +
      8273  VmaDefragmentationContext context);
      +
      8274 
      +
      8275  void GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo);
      +
      8276  bool TouchAllocation(VmaAllocation hAllocation);
      +
      8277 
      +
      8278  VkResult CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPool* pPool);
      +
      8279  void DestroyPool(VmaPool pool);
      +
      8280  void GetPoolStats(VmaPool pool, VmaPoolStats* pPoolStats);
      +
      8281 
      +
      8282  void SetCurrentFrameIndex(uint32_t frameIndex);
      +
      8283  uint32_t GetCurrentFrameIndex() const { return m_CurrentFrameIndex.load(); }
      +
      8284 
      +
      8285  void MakePoolAllocationsLost(
      +
      8286  VmaPool hPool,
      +
      8287  size_t* pLostAllocationCount);
      +
      8288  VkResult CheckPoolCorruption(VmaPool hPool);
      +
      8289  VkResult CheckCorruption(uint32_t memoryTypeBits);
      8290 
      -
      8291 void VmaStringBuilder::AddNumber(uint64_t num)
      -
      8292 {
      -
      8293  char buf[21];
      -
      8294  buf[20] = '\0';
      -
      8295  char *p = &buf[20];
      -
      8296  do
      -
      8297  {
      -
      8298  *--p = '0' + (num % 10);
      -
      8299  num /= 10;
      -
      8300  }
      -
      8301  while(num);
      -
      8302  Add(p);
      -
      8303 }
      -
      8304 
      -
      8305 void VmaStringBuilder::AddPointer(const void* ptr)
      -
      8306 {
      -
      8307  char buf[21];
      -
      8308  VmaPtrToStr(buf, sizeof(buf), ptr);
      -
      8309  Add(buf);
      -
      8310 }
      -
      8311 
      -
      8312 #endif // #if VMA_STATS_STRING_ENABLED
      -
      8313 
      -
      8315 // VmaJsonWriter
      -
      8316 
      -
      8317 #if VMA_STATS_STRING_ENABLED
      -
      8318 
      -
      8319 class VmaJsonWriter
      -
      8320 {
      -
      8321  VMA_CLASS_NO_COPY(VmaJsonWriter)
      -
      8322 public:
      -
      8323  VmaJsonWriter(const VkAllocationCallbacks* pAllocationCallbacks, VmaStringBuilder& sb);
      -
      8324  ~VmaJsonWriter();
      -
      8325 
      -
      8326  void BeginObject(bool singleLine = false);
      -
      8327  void EndObject();
      -
      8328 
      -
      8329  void BeginArray(bool singleLine = false);
      -
      8330  void EndArray();
      -
      8331 
      -
      8332  void WriteString(const char* pStr);
      -
      8333  void BeginString(const char* pStr = VMA_NULL);
      -
      8334  void ContinueString(const char* pStr);
      -
      8335  void ContinueString(uint32_t n);
      -
      8336  void ContinueString(uint64_t n);
      -
      8337  void ContinueString_Pointer(const void* ptr);
      -
      8338  void EndString(const char* pStr = VMA_NULL);
      -
      8339 
      -
      8340  void WriteNumber(uint32_t n);
      -
      8341  void WriteNumber(uint64_t n);
      -
      8342  void WriteBool(bool b);
      -
      8343  void WriteNull();
      +
      8291  void CreateLostAllocation(VmaAllocation* pAllocation);
      +
      8292 
      +
      8293  // Call to Vulkan function vkAllocateMemory with accompanying bookkeeping.
      +
      8294  VkResult AllocateVulkanMemory(const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory);
      +
      8295  // Call to Vulkan function vkFreeMemory with accompanying bookkeeping.
      +
      8296  void FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, VkDeviceMemory hMemory);
      +
      8297  // Call to Vulkan function vkBindBufferMemory or vkBindBufferMemory2KHR.
      +
      8298  VkResult BindVulkanBuffer(
      +
      8299  VkDeviceMemory memory,
      +
      8300  VkDeviceSize memoryOffset,
      +
      8301  VkBuffer buffer,
      +
      8302  const void* pNext);
      +
      8303  // Call to Vulkan function vkBindImageMemory or vkBindImageMemory2KHR.
      +
      8304  VkResult BindVulkanImage(
      +
      8305  VkDeviceMemory memory,
      +
      8306  VkDeviceSize memoryOffset,
      +
      8307  VkImage image,
      +
      8308  const void* pNext);
      +
      8309 
      +
      8310  VkResult Map(VmaAllocation hAllocation, void** ppData);
      +
      8311  void Unmap(VmaAllocation hAllocation);
      +
      8312 
      +
      8313  VkResult BindBufferMemory(
      +
      8314  VmaAllocation hAllocation,
      +
      8315  VkDeviceSize allocationLocalOffset,
      +
      8316  VkBuffer hBuffer,
      +
      8317  const void* pNext);
      +
      8318  VkResult BindImageMemory(
      +
      8319  VmaAllocation hAllocation,
      +
      8320  VkDeviceSize allocationLocalOffset,
      +
      8321  VkImage hImage,
      +
      8322  const void* pNext);
      +
      8323 
      +
      8324  VkResult FlushOrInvalidateAllocation(
      +
      8325  VmaAllocation hAllocation,
      +
      8326  VkDeviceSize offset, VkDeviceSize size,
      +
      8327  VMA_CACHE_OPERATION op);
      +
      8328  VkResult FlushOrInvalidateAllocations(
      +
      8329  uint32_t allocationCount,
      +
      8330  const VmaAllocation* allocations,
      +
      8331  const VkDeviceSize* offsets, const VkDeviceSize* sizes,
      +
      8332  VMA_CACHE_OPERATION op);
      +
      8333 
      +
      8334  void FillAllocation(const VmaAllocation hAllocation, uint8_t pattern);
      +
      8335 
      +
      8336  /*
      +
      8337  Returns bit mask of memory types that can support defragmentation on GPU as
      +
      8338  they support creation of required buffer for copy operations.
      +
      8339  */
      +
      8340  uint32_t GetGpuDefragmentationMemoryTypeBits();
      +
      8341 
      +
      8342 private:
      +
      8343  VkDeviceSize m_PreferredLargeHeapBlockSize;
      8344 
      -
      8345 private:
      -
      8346  static const char* const INDENT;
      -
      8347 
      -
      8348  enum COLLECTION_TYPE
      -
      8349  {
      -
      8350  COLLECTION_TYPE_OBJECT,
      -
      8351  COLLECTION_TYPE_ARRAY,
      -
      8352  };
      -
      8353  struct StackItem
      -
      8354  {
      -
      8355  COLLECTION_TYPE type;
      -
      8356  uint32_t valueCount;
      -
      8357  bool singleLineMode;
      -
      8358  };
      +
      8345  VkPhysicalDevice m_PhysicalDevice;
      +
      8346  VMA_ATOMIC_UINT32 m_CurrentFrameIndex;
      +
      8347  VMA_ATOMIC_UINT32 m_GpuDefragmentationMemoryTypeBits; // UINT32_MAX means uninitialized.
      +
      8348 
      +
      8349  VMA_RW_MUTEX m_PoolsMutex;
      +
      8350  typedef VmaIntrusiveLinkedList<VmaPoolListItemTraits> PoolList;
      +
      8351  // Protected by m_PoolsMutex.
      +
      8352  PoolList m_Pools;
      +
      8353  uint32_t m_NextPoolId;
      +
      8354 
      +
      8355  VmaVulkanFunctions m_VulkanFunctions;
      +
      8356 
      +
      8357  // Global bit mask AND-ed with any memoryTypeBits to disallow certain memory types.
      +
      8358  uint32_t m_GlobalMemoryTypeBits;
      8359 
      -
      8360  VmaStringBuilder& m_SB;
      -
      8361  VmaVector< StackItem, VmaStlAllocator<StackItem> > m_Stack;
      -
      8362  bool m_InsideString;
      +
      8360 #if VMA_RECORDING_ENABLED
      +
      8361  VmaRecorder* m_pRecorder;
      +
      8362 #endif
      8363 
      -
      8364  void BeginValue(bool isString);
      -
      8365  void WriteIndent(bool oneLess = false);
      -
      8366 };
      -
      8367 
      -
      8368 const char* const VmaJsonWriter::INDENT = " ";
      +
      8364  void ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunctions);
      +
      8365 
      +
      8366 #if VMA_STATIC_VULKAN_FUNCTIONS == 1
      +
      8367  void ImportVulkanFunctions_Static();
      +
      8368 #endif
      8369 
      -
      8370 VmaJsonWriter::VmaJsonWriter(const VkAllocationCallbacks* pAllocationCallbacks, VmaStringBuilder& sb) :
      -
      8371  m_SB(sb),
      -
      8372  m_Stack(VmaStlAllocator<StackItem>(pAllocationCallbacks)),
      -
      8373  m_InsideString(false)
      -
      8374 {
      -
      8375 }
      -
      8376 
      -
      8377 VmaJsonWriter::~VmaJsonWriter()
      -
      8378 {
      -
      8379  VMA_ASSERT(!m_InsideString);
      -
      8380  VMA_ASSERT(m_Stack.empty());
      -
      8381 }
      -
      8382 
      -
      8383 void VmaJsonWriter::BeginObject(bool singleLine)
      -
      8384 {
      -
      8385  VMA_ASSERT(!m_InsideString);
      -
      8386 
      -
      8387  BeginValue(false);
      -
      8388  m_SB.Add('{');
      -
      8389 
      -
      8390  StackItem item;
      -
      8391  item.type = COLLECTION_TYPE_OBJECT;
      -
      8392  item.valueCount = 0;
      -
      8393  item.singleLineMode = singleLine;
      -
      8394  m_Stack.push_back(item);
      -
      8395 }
      -
      8396 
      -
      8397 void VmaJsonWriter::EndObject()
      -
      8398 {
      -
      8399  VMA_ASSERT(!m_InsideString);
      -
      8400 
      -
      8401  WriteIndent(true);
      -
      8402  m_SB.Add('}');
      +
      8370  void ImportVulkanFunctions_Custom(const VmaVulkanFunctions* pVulkanFunctions);
      +
      8371 
      +
      8372 #if VMA_DYNAMIC_VULKAN_FUNCTIONS == 1
      +
      8373  void ImportVulkanFunctions_Dynamic();
      +
      8374 #endif
      +
      8375 
      +
      8376  void ValidateVulkanFunctions();
      +
      8377 
      +
      8378  VkDeviceSize CalcPreferredBlockSize(uint32_t memTypeIndex);
      +
      8379 
      +
      8380  VkResult AllocateMemoryOfType(
      +
      8381  VkDeviceSize size,
      +
      8382  VkDeviceSize alignment,
      +
      8383  bool dedicatedAllocation,
      +
      8384  VkBuffer dedicatedBuffer,
      +
      8385  VkBufferUsageFlags dedicatedBufferUsage,
      +
      8386  VkImage dedicatedImage,
      +
      8387  const VmaAllocationCreateInfo& createInfo,
      +
      8388  uint32_t memTypeIndex,
      +
      8389  VmaSuballocationType suballocType,
      +
      8390  size_t allocationCount,
      +
      8391  VmaAllocation* pAllocations);
      +
      8392 
      +
      8393  // Helper function only to be used inside AllocateDedicatedMemory.
      +
      8394  VkResult AllocateDedicatedMemoryPage(
      +
      8395  VkDeviceSize size,
      +
      8396  VmaSuballocationType suballocType,
      +
      8397  uint32_t memTypeIndex,
      +
      8398  const VkMemoryAllocateInfo& allocInfo,
      +
      8399  bool map,
      +
      8400  bool isUserDataString,
      +
      8401  void* pUserData,
      +
      8402  VmaAllocation* pAllocation);
      8403 
      -
      8404  VMA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_OBJECT);
      -
      8405  m_Stack.pop_back();
      -
      8406 }
      -
      8407 
      -
      8408 void VmaJsonWriter::BeginArray(bool singleLine)
      -
      8409 {
      -
      8410  VMA_ASSERT(!m_InsideString);
      -
      8411 
      -
      8412  BeginValue(false);
      -
      8413  m_SB.Add('[');
      -
      8414 
      -
      8415  StackItem item;
      -
      8416  item.type = COLLECTION_TYPE_ARRAY;
      -
      8417  item.valueCount = 0;
      -
      8418  item.singleLineMode = singleLine;
      -
      8419  m_Stack.push_back(item);
      -
      8420 }
      +
      8404  // Allocates and registers new VkDeviceMemory specifically for dedicated allocations.
      +
      8405  VkResult AllocateDedicatedMemory(
      +
      8406  VkDeviceSize size,
      +
      8407  VmaSuballocationType suballocType,
      +
      8408  uint32_t memTypeIndex,
      +
      8409  bool withinBudget,
      +
      8410  bool map,
      +
      8411  bool isUserDataString,
      +
      8412  void* pUserData,
      +
      8413  float priority,
      +
      8414  VkBuffer dedicatedBuffer,
      +
      8415  VkBufferUsageFlags dedicatedBufferUsage,
      +
      8416  VkImage dedicatedImage,
      +
      8417  size_t allocationCount,
      +
      8418  VmaAllocation* pAllocations);
      +
      8419 
      +
      8420  void FreeDedicatedMemory(const VmaAllocation allocation);
      8421 
      -
      8422 void VmaJsonWriter::EndArray()
      -
      8423 {
      -
      8424  VMA_ASSERT(!m_InsideString);
      -
      8425 
      -
      8426  WriteIndent(true);
      -
      8427  m_SB.Add(']');
      -
      8428 
      -
      8429  VMA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_ARRAY);
      -
      8430  m_Stack.pop_back();
      -
      8431 }
      -
      8432 
      -
      8433 void VmaJsonWriter::WriteString(const char* pStr)
      -
      8434 {
      -
      8435  BeginString(pStr);
      -
      8436  EndString();
      -
      8437 }
      -
      8438 
      -
      8439 void VmaJsonWriter::BeginString(const char* pStr)
      -
      8440 {
      -
      8441  VMA_ASSERT(!m_InsideString);
      +
      8422  /*
      +
      8423  Calculates and returns bit mask of memory types that can support defragmentation
      +
      8424  on GPU as they support creation of required buffer for copy operations.
      +
      8425  */
      +
      8426  uint32_t CalculateGpuDefragmentationMemoryTypeBits() const;
      +
      8427 
      +
      8428  uint32_t CalculateGlobalMemoryTypeBits() const;
      +
      8429 
      +
      8430  bool GetFlushOrInvalidateRange(
      +
      8431  VmaAllocation allocation,
      +
      8432  VkDeviceSize offset, VkDeviceSize size,
      +
      8433  VkMappedMemoryRange& outRange) const;
      +
      8434 
      +
      8435 #if VMA_MEMORY_BUDGET
      +
      8436  void UpdateVulkanBudget();
      +
      8437 #endif // #if VMA_MEMORY_BUDGET
      +
      8438 };
      +
      8439 
      +
      8441 // Memory allocation #2 after VmaAllocator_T definition
      8442 
      -
      8443  BeginValue(true);
      -
      8444  m_SB.Add('"');
      -
      8445  m_InsideString = true;
      -
      8446  if(pStr != VMA_NULL && pStr[0] != '\0')
      -
      8447  {
      -
      8448  ContinueString(pStr);
      -
      8449  }
      -
      8450 }
      -
      8451 
      -
      8452 void VmaJsonWriter::ContinueString(const char* pStr)
      -
      8453 {
      -
      8454  VMA_ASSERT(m_InsideString);
      -
      8455 
      -
      8456  const size_t strLen = strlen(pStr);
      -
      8457  for(size_t i = 0; i < strLen; ++i)
      -
      8458  {
      -
      8459  char ch = pStr[i];
      -
      8460  if(ch == '\\')
      -
      8461  {
      -
      8462  m_SB.Add("\\\\");
      -
      8463  }
      -
      8464  else if(ch == '"')
      -
      8465  {
      -
      8466  m_SB.Add("\\\"");
      -
      8467  }
      -
      8468  else if(ch >= 32)
      -
      8469  {
      -
      8470  m_SB.Add(ch);
      -
      8471  }
      -
      8472  else switch(ch)
      -
      8473  {
      -
      8474  case '\b':
      -
      8475  m_SB.Add("\\b");
      -
      8476  break;
      -
      8477  case '\f':
      -
      8478  m_SB.Add("\\f");
      -
      8479  break;
      -
      8480  case '\n':
      -
      8481  m_SB.Add("\\n");
      -
      8482  break;
      -
      8483  case '\r':
      -
      8484  m_SB.Add("\\r");
      -
      8485  break;
      -
      8486  case '\t':
      -
      8487  m_SB.Add("\\t");
      -
      8488  break;
      -
      8489  default:
      -
      8490  VMA_ASSERT(0 && "Character not currently supported.");
      -
      8491  break;
      -
      8492  }
      -
      8493  }
      -
      8494 }
      -
      8495 
      -
      8496 void VmaJsonWriter::ContinueString(uint32_t n)
      -
      8497 {
      -
      8498  VMA_ASSERT(m_InsideString);
      -
      8499  m_SB.AddNumber(n);
      -
      8500 }
      -
      8501 
      -
      8502 void VmaJsonWriter::ContinueString(uint64_t n)
      -
      8503 {
      -
      8504  VMA_ASSERT(m_InsideString);
      -
      8505  m_SB.AddNumber(n);
      -
      8506 }
      -
      8507 
      -
      8508 void VmaJsonWriter::ContinueString_Pointer(const void* ptr)
      -
      8509 {
      -
      8510  VMA_ASSERT(m_InsideString);
      -
      8511  m_SB.AddPointer(ptr);
      -
      8512 }
      -
      8513 
      -
      8514 void VmaJsonWriter::EndString(const char* pStr)
      -
      8515 {
      -
      8516  VMA_ASSERT(m_InsideString);
      -
      8517  if(pStr != VMA_NULL && pStr[0] != '\0')
      -
      8518  {
      -
      8519  ContinueString(pStr);
      -
      8520  }
      -
      8521  m_SB.Add('"');
      -
      8522  m_InsideString = false;
      -
      8523 }
      -
      8524 
      -
      8525 void VmaJsonWriter::WriteNumber(uint32_t n)
      -
      8526 {
      -
      8527  VMA_ASSERT(!m_InsideString);
      -
      8528  BeginValue(false);
      -
      8529  m_SB.AddNumber(n);
      -
      8530 }
      -
      8531 
      -
      8532 void VmaJsonWriter::WriteNumber(uint64_t n)
      -
      8533 {
      -
      8534  VMA_ASSERT(!m_InsideString);
      -
      8535  BeginValue(false);
      -
      8536  m_SB.AddNumber(n);
      -
      8537 }
      -
      8538 
      -
      8539 void VmaJsonWriter::WriteBool(bool b)
      -
      8540 {
      -
      8541  VMA_ASSERT(!m_InsideString);
      -
      8542  BeginValue(false);
      -
      8543  m_SB.Add(b ? "true" : "false");
      -
      8544 }
      -
      8545 
      -
      8546 void VmaJsonWriter::WriteNull()
      -
      8547 {
      -
      8548  VMA_ASSERT(!m_InsideString);
      -
      8549  BeginValue(false);
      -
      8550  m_SB.Add("null");
      -
      8551 }
      -
      8552 
      -
      8553 void VmaJsonWriter::BeginValue(bool isString)
      -
      8554 {
      -
      8555  if(!m_Stack.empty())
      -
      8556  {
      -
      8557  StackItem& currItem = m_Stack.back();
      -
      8558  if(currItem.type == COLLECTION_TYPE_OBJECT &&
      -
      8559  currItem.valueCount % 2 == 0)
      -
      8560  {
      -
      8561  VMA_ASSERT(isString);
      -
      8562  }
      -
      8563 
      -
      8564  if(currItem.type == COLLECTION_TYPE_OBJECT &&
      -
      8565  currItem.valueCount % 2 != 0)
      -
      8566  {
      -
      8567  m_SB.Add(": ");
      -
      8568  }
      -
      8569  else if(currItem.valueCount > 0)
      -
      8570  {
      -
      8571  m_SB.Add(", ");
      -
      8572  WriteIndent();
      -
      8573  }
      -
      8574  else
      -
      8575  {
      -
      8576  WriteIndent();
      -
      8577  }
      -
      8578  ++currItem.valueCount;
      -
      8579  }
      -
      8580 }
      -
      8581 
      -
      8582 void VmaJsonWriter::WriteIndent(bool oneLess)
      -
      8583 {
      -
      8584  if(!m_Stack.empty() && !m_Stack.back().singleLineMode)
      -
      8585  {
      -
      8586  m_SB.AddNewLine();
      +
      8443 static void* VmaMalloc(VmaAllocator hAllocator, size_t size, size_t alignment)
      +
      8444 {
      +
      8445  return VmaMalloc(&hAllocator->m_AllocationCallbacks, size, alignment);
      +
      8446 }
      +
      8447 
      +
      8448 static void VmaFree(VmaAllocator hAllocator, void* ptr)
      +
      8449 {
      +
      8450  VmaFree(&hAllocator->m_AllocationCallbacks, ptr);
      +
      8451 }
      +
      8452 
      +
      8453 template<typename T>
      +
      8454 static T* VmaAllocate(VmaAllocator hAllocator)
      +
      8455 {
      +
      8456  return (T*)VmaMalloc(hAllocator, sizeof(T), VMA_ALIGN_OF(T));
      +
      8457 }
      +
      8458 
      +
      8459 template<typename T>
      +
      8460 static T* VmaAllocateArray(VmaAllocator hAllocator, size_t count)
      +
      8461 {
      +
      8462  return (T*)VmaMalloc(hAllocator, sizeof(T) * count, VMA_ALIGN_OF(T));
      +
      8463 }
      +
      8464 
      +
      8465 template<typename T>
      +
      8466 static void vma_delete(VmaAllocator hAllocator, T* ptr)
      +
      8467 {
      +
      8468  if(ptr != VMA_NULL)
      +
      8469  {
      +
      8470  ptr->~T();
      +
      8471  VmaFree(hAllocator, ptr);
      +
      8472  }
      +
      8473 }
      +
      8474 
      +
      8475 template<typename T>
      +
      8476 static void vma_delete_array(VmaAllocator hAllocator, T* ptr, size_t count)
      +
      8477 {
      +
      8478  if(ptr != VMA_NULL)
      +
      8479  {
      +
      8480  for(size_t i = count; i--; )
      +
      8481  ptr[i].~T();
      +
      8482  VmaFree(hAllocator, ptr);
      +
      8483  }
      +
      8484 }
      +
      8485 
      +
      8487 // VmaStringBuilder
      +
      8488 
      +
      8489 #if VMA_STATS_STRING_ENABLED
      +
      8490 
      +
      8491 class VmaStringBuilder
      +
      8492 {
      +
      8493 public:
      +
      8494  VmaStringBuilder(VmaAllocator alloc) : m_Data(VmaStlAllocator<char>(alloc->GetAllocationCallbacks())) { }
      +
      8495  size_t GetLength() const { return m_Data.size(); }
      +
      8496  const char* GetData() const { return m_Data.data(); }
      +
      8497 
      +
      8498  void Add(char ch) { m_Data.push_back(ch); }
      +
      8499  void Add(const char* pStr);
      +
      8500  void AddNewLine() { Add('\n'); }
      +
      8501  void AddNumber(uint32_t num);
      +
      8502  void AddNumber(uint64_t num);
      +
      8503  void AddPointer(const void* ptr);
      +
      8504 
      +
      8505 private:
      +
      8506  VmaVector< char, VmaStlAllocator<char> > m_Data;
      +
      8507 };
      +
      8508 
      +
      8509 void VmaStringBuilder::Add(const char* pStr)
      +
      8510 {
      +
      8511  const size_t strLen = strlen(pStr);
      +
      8512  if(strLen > 0)
      +
      8513  {
      +
      8514  const size_t oldCount = m_Data.size();
      +
      8515  m_Data.resize(oldCount + strLen);
      +
      8516  memcpy(m_Data.data() + oldCount, pStr, strLen);
      +
      8517  }
      +
      8518 }
      +
      8519 
      +
      8520 void VmaStringBuilder::AddNumber(uint32_t num)
      +
      8521 {
      +
      8522  char buf[11];
      +
      8523  buf[10] = '\0';
      +
      8524  char *p = &buf[10];
      +
      8525  do
      +
      8526  {
      +
      8527  *--p = '0' + (num % 10);
      +
      8528  num /= 10;
      +
      8529  }
      +
      8530  while(num);
      +
      8531  Add(p);
      +
      8532 }
      +
      8533 
      +
      8534 void VmaStringBuilder::AddNumber(uint64_t num)
      +
      8535 {
      +
      8536  char buf[21];
      +
      8537  buf[20] = '\0';
      +
      8538  char *p = &buf[20];
      +
      8539  do
      +
      8540  {
      +
      8541  *--p = '0' + (num % 10);
      +
      8542  num /= 10;
      +
      8543  }
      +
      8544  while(num);
      +
      8545  Add(p);
      +
      8546 }
      +
      8547 
      +
      8548 void VmaStringBuilder::AddPointer(const void* ptr)
      +
      8549 {
      +
      8550  char buf[21];
      +
      8551  VmaPtrToStr(buf, sizeof(buf), ptr);
      +
      8552  Add(buf);
      +
      8553 }
      +
      8554 
      +
      8555 #endif // #if VMA_STATS_STRING_ENABLED
      +
      8556 
      +
      8558 // VmaJsonWriter
      +
      8559 
      +
      8560 #if VMA_STATS_STRING_ENABLED
      +
      8561 
      +
      8562 class VmaJsonWriter
      +
      8563 {
      +
      8564  VMA_CLASS_NO_COPY(VmaJsonWriter)
      +
      8565 public:
      +
      8566  VmaJsonWriter(const VkAllocationCallbacks* pAllocationCallbacks, VmaStringBuilder& sb);
      +
      8567  ~VmaJsonWriter();
      +
      8568 
      +
      8569  void BeginObject(bool singleLine = false);
      +
      8570  void EndObject();
      +
      8571 
      +
      8572  void BeginArray(bool singleLine = false);
      +
      8573  void EndArray();
      +
      8574 
      +
      8575  void WriteString(const char* pStr);
      +
      8576  void BeginString(const char* pStr = VMA_NULL);
      +
      8577  void ContinueString(const char* pStr);
      +
      8578  void ContinueString(uint32_t n);
      +
      8579  void ContinueString(uint64_t n);
      +
      8580  void ContinueString_Pointer(const void* ptr);
      +
      8581  void EndString(const char* pStr = VMA_NULL);
      +
      8582 
      +
      8583  void WriteNumber(uint32_t n);
      +
      8584  void WriteNumber(uint64_t n);
      +
      8585  void WriteBool(bool b);
      +
      8586  void WriteNull();
      8587 
      -
      8588  size_t count = m_Stack.size();
      -
      8589  if(count > 0 && oneLess)
      -
      8590  {
      -
      8591  --count;
      -
      8592  }
      -
      8593  for(size_t i = 0; i < count; ++i)
      -
      8594  {
      -
      8595  m_SB.Add(INDENT);
      -
      8596  }
      -
      8597  }
      -
      8598 }
      -
      8599 
      -
      8600 #endif // #if VMA_STATS_STRING_ENABLED
      -
      8601 
      -
      8603 
      -
      8604 void VmaAllocation_T::SetUserData(VmaAllocator hAllocator, void* pUserData)
      -
      8605 {
      -
      8606  if(IsUserDataString())
      -
      8607  {
      -
      8608  VMA_ASSERT(pUserData == VMA_NULL || pUserData != m_pUserData);
      -
      8609 
      -
      8610  FreeUserDataString(hAllocator);
      -
      8611 
      -
      8612  if(pUserData != VMA_NULL)
      -
      8613  {
      -
      8614  m_pUserData = VmaCreateStringCopy(hAllocator->GetAllocationCallbacks(), (const char*)pUserData);
      -
      8615  }
      -
      8616  }
      -
      8617  else
      -
      8618  {
      -
      8619  m_pUserData = pUserData;
      -
      8620  }
      -
      8621 }
      -
      8622 
      -
      8623 void VmaAllocation_T::ChangeBlockAllocation(
      -
      8624  VmaAllocator hAllocator,
      -
      8625  VmaDeviceMemoryBlock* block,
      -
      8626  VkDeviceSize offset)
      +
      8588 private:
      +
      8589  static const char* const INDENT;
      +
      8590 
      +
      8591  enum COLLECTION_TYPE
      +
      8592  {
      +
      8593  COLLECTION_TYPE_OBJECT,
      +
      8594  COLLECTION_TYPE_ARRAY,
      +
      8595  };
      +
      8596  struct StackItem
      +
      8597  {
      +
      8598  COLLECTION_TYPE type;
      +
      8599  uint32_t valueCount;
      +
      8600  bool singleLineMode;
      +
      8601  };
      +
      8602 
      +
      8603  VmaStringBuilder& m_SB;
      +
      8604  VmaVector< StackItem, VmaStlAllocator<StackItem> > m_Stack;
      +
      8605  bool m_InsideString;
      +
      8606 
      +
      8607  void BeginValue(bool isString);
      +
      8608  void WriteIndent(bool oneLess = false);
      +
      8609 };
      +
      8610 
      +
      8611 const char* const VmaJsonWriter::INDENT = " ";
      +
      8612 
      +
      8613 VmaJsonWriter::VmaJsonWriter(const VkAllocationCallbacks* pAllocationCallbacks, VmaStringBuilder& sb) :
      +
      8614  m_SB(sb),
      +
      8615  m_Stack(VmaStlAllocator<StackItem>(pAllocationCallbacks)),
      +
      8616  m_InsideString(false)
      +
      8617 {
      +
      8618 }
      +
      8619 
      +
      8620 VmaJsonWriter::~VmaJsonWriter()
      +
      8621 {
      +
      8622  VMA_ASSERT(!m_InsideString);
      +
      8623  VMA_ASSERT(m_Stack.empty());
      +
      8624 }
      +
      8625 
      +
      8626 void VmaJsonWriter::BeginObject(bool singleLine)
      8627 {
      -
      8628  VMA_ASSERT(block != VMA_NULL);
      -
      8629  VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK);
      -
      8630 
      -
      8631  // Move mapping reference counter from old block to new block.
      -
      8632  if(block != m_BlockAllocation.m_Block)
      -
      8633  {
      -
      8634  uint32_t mapRefCount = m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP;
      -
      8635  if(IsPersistentMap())
      -
      8636  ++mapRefCount;
      -
      8637  m_BlockAllocation.m_Block->Unmap(hAllocator, mapRefCount);
      -
      8638  block->Map(hAllocator, mapRefCount, VMA_NULL);
      -
      8639  }
      -
      8640 
      -
      8641  m_BlockAllocation.m_Block = block;
      -
      8642  m_BlockAllocation.m_Offset = offset;
      -
      8643 }
      -
      8644 
      -
      8645 void VmaAllocation_T::ChangeOffset(VkDeviceSize newOffset)
      -
      8646 {
      -
      8647  VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK);
      -
      8648  m_BlockAllocation.m_Offset = newOffset;
      +
      8628  VMA_ASSERT(!m_InsideString);
      +
      8629 
      +
      8630  BeginValue(false);
      +
      8631  m_SB.Add('{');
      +
      8632 
      +
      8633  StackItem item;
      +
      8634  item.type = COLLECTION_TYPE_OBJECT;
      +
      8635  item.valueCount = 0;
      +
      8636  item.singleLineMode = singleLine;
      +
      8637  m_Stack.push_back(item);
      +
      8638 }
      +
      8639 
      +
      8640 void VmaJsonWriter::EndObject()
      +
      8641 {
      +
      8642  VMA_ASSERT(!m_InsideString);
      +
      8643 
      +
      8644  WriteIndent(true);
      +
      8645  m_SB.Add('}');
      +
      8646 
      +
      8647  VMA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_OBJECT);
      +
      8648  m_Stack.pop_back();
      8649 }
      8650 
      -
      8651 VkDeviceSize VmaAllocation_T::GetOffset() const
      -
      8652 {
      -
      8653  switch(m_Type)
      -
      8654  {
      -
      8655  case ALLOCATION_TYPE_BLOCK:
      -
      8656  return m_BlockAllocation.m_Offset;
      -
      8657  case ALLOCATION_TYPE_DEDICATED:
      -
      8658  return 0;
      -
      8659  default:
      -
      8660  VMA_ASSERT(0);
      -
      8661  return 0;
      -
      8662  }
      +
      8651 void VmaJsonWriter::BeginArray(bool singleLine)
      +
      8652 {
      +
      8653  VMA_ASSERT(!m_InsideString);
      +
      8654 
      +
      8655  BeginValue(false);
      +
      8656  m_SB.Add('[');
      +
      8657 
      +
      8658  StackItem item;
      +
      8659  item.type = COLLECTION_TYPE_ARRAY;
      +
      8660  item.valueCount = 0;
      +
      8661  item.singleLineMode = singleLine;
      +
      8662  m_Stack.push_back(item);
      8663 }
      8664 
      -
      8665 VkDeviceMemory VmaAllocation_T::GetMemory() const
      -
      8666 {
      -
      8667  switch(m_Type)
      -
      8668  {
      -
      8669  case ALLOCATION_TYPE_BLOCK:
      -
      8670  return m_BlockAllocation.m_Block->GetDeviceMemory();
      -
      8671  case ALLOCATION_TYPE_DEDICATED:
      -
      8672  return m_DedicatedAllocation.m_hMemory;
      -
      8673  default:
      -
      8674  VMA_ASSERT(0);
      -
      8675  return VK_NULL_HANDLE;
      -
      8676  }
      -
      8677 }
      -
      8678 
      -
      8679 void* VmaAllocation_T::GetMappedData() const
      -
      8680 {
      -
      8681  switch(m_Type)
      -
      8682  {
      -
      8683  case ALLOCATION_TYPE_BLOCK:
      -
      8684  if(m_MapCount != 0)
      -
      8685  {
      -
      8686  void* pBlockData = m_BlockAllocation.m_Block->GetMappedData();
      -
      8687  VMA_ASSERT(pBlockData != VMA_NULL);
      -
      8688  return (char*)pBlockData + m_BlockAllocation.m_Offset;
      -
      8689  }
      -
      8690  else
      -
      8691  {
      -
      8692  return VMA_NULL;
      -
      8693  }
      -
      8694  break;
      -
      8695  case ALLOCATION_TYPE_DEDICATED:
      -
      8696  VMA_ASSERT((m_DedicatedAllocation.m_pMappedData != VMA_NULL) == (m_MapCount != 0));
      -
      8697  return m_DedicatedAllocation.m_pMappedData;
      -
      8698  default:
      -
      8699  VMA_ASSERT(0);
      -
      8700  return VMA_NULL;
      -
      8701  }
      -
      8702 }
      -
      8703 
      -
      8704 bool VmaAllocation_T::CanBecomeLost() const
      -
      8705 {
      -
      8706  switch(m_Type)
      -
      8707  {
      -
      8708  case ALLOCATION_TYPE_BLOCK:
      -
      8709  return m_BlockAllocation.m_CanBecomeLost;
      -
      8710  case ALLOCATION_TYPE_DEDICATED:
      -
      8711  return false;
      -
      8712  default:
      -
      8713  VMA_ASSERT(0);
      -
      8714  return false;
      -
      8715  }
      -
      8716 }
      -
      8717 
      -
      8718 bool VmaAllocation_T::MakeLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)
      -
      8719 {
      -
      8720  VMA_ASSERT(CanBecomeLost());
      -
      8721 
      -
      8722  /*
      -
      8723  Warning: This is a carefully designed algorithm.
      -
      8724  Do not modify unless you really know what you're doing :)
      -
      8725  */
      -
      8726  uint32_t localLastUseFrameIndex = GetLastUseFrameIndex();
      -
      8727  for(;;)
      -
      8728  {
      -
      8729  if(localLastUseFrameIndex == VMA_FRAME_INDEX_LOST)
      -
      8730  {
      -
      8731  VMA_ASSERT(0);
      -
      8732  return false;
      -
      8733  }
      -
      8734  else if(localLastUseFrameIndex + frameInUseCount >= currentFrameIndex)
      -
      8735  {
      -
      8736  return false;
      -
      8737  }
      -
      8738  else // Last use time earlier than current time.
      -
      8739  {
      -
      8740  if(CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, VMA_FRAME_INDEX_LOST))
      -
      8741  {
      -
      8742  // Setting hAllocation.LastUseFrameIndex atomic to VMA_FRAME_INDEX_LOST is enough to mark it as LOST.
      -
      8743  // Calling code just needs to unregister this allocation in owning VmaDeviceMemoryBlock.
      -
      8744  return true;
      -
      8745  }
      -
      8746  }
      -
      8747  }
      -
      8748 }
      -
      8749 
      -
      8750 #if VMA_STATS_STRING_ENABLED
      -
      8751 
      -
      8752 // Correspond to values of enum VmaSuballocationType.
      -
      8753 static const char* VMA_SUBALLOCATION_TYPE_NAMES[] = {
      -
      8754  "FREE",
      -
      8755  "UNKNOWN",
      -
      8756  "BUFFER",
      -
      8757  "IMAGE_UNKNOWN",
      -
      8758  "IMAGE_LINEAR",
      -
      8759  "IMAGE_OPTIMAL",
      -
      8760 };
      -
      8761 
      -
      8762 void VmaAllocation_T::PrintParameters(class VmaJsonWriter& json) const
      -
      8763 {
      -
      8764  json.WriteString("Type");
      -
      8765  json.WriteString(VMA_SUBALLOCATION_TYPE_NAMES[m_SuballocationType]);
      -
      8766 
      -
      8767  json.WriteString("Size");
      -
      8768  json.WriteNumber(m_Size);
      -
      8769 
      -
      8770  if(m_pUserData != VMA_NULL)
      -
      8771  {
      -
      8772  json.WriteString("UserData");
      -
      8773  if(IsUserDataString())
      -
      8774  {
      -
      8775  json.WriteString((const char*)m_pUserData);
      -
      8776  }
      -
      8777  else
      -
      8778  {
      -
      8779  json.BeginString();
      -
      8780  json.ContinueString_Pointer(m_pUserData);
      -
      8781  json.EndString();
      -
      8782  }
      -
      8783  }
      -
      8784 
      -
      8785  json.WriteString("CreationFrameIndex");
      -
      8786  json.WriteNumber(m_CreationFrameIndex);
      -
      8787 
      -
      8788  json.WriteString("LastUseFrameIndex");
      -
      8789  json.WriteNumber(GetLastUseFrameIndex());
      -
      8790 
      -
      8791  if(m_BufferImageUsage != 0)
      -
      8792  {
      -
      8793  json.WriteString("Usage");
      -
      8794  json.WriteNumber(m_BufferImageUsage);
      -
      8795  }
      -
      8796 }
      -
      8797 
      -
      8798 #endif
      -
      8799 
      -
      8800 void VmaAllocation_T::FreeUserDataString(VmaAllocator hAllocator)
      -
      8801 {
      -
      8802  VMA_ASSERT(IsUserDataString());
      -
      8803  VmaFreeString(hAllocator->GetAllocationCallbacks(), (char*)m_pUserData);
      -
      8804  m_pUserData = VMA_NULL;
      -
      8805 }
      +
      8665 void VmaJsonWriter::EndArray()
      +
      8666 {
      +
      8667  VMA_ASSERT(!m_InsideString);
      +
      8668 
      +
      8669  WriteIndent(true);
      +
      8670  m_SB.Add(']');
      +
      8671 
      +
      8672  VMA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_ARRAY);
      +
      8673  m_Stack.pop_back();
      +
      8674 }
      +
      8675 
      +
      8676 void VmaJsonWriter::WriteString(const char* pStr)
      +
      8677 {
      +
      8678  BeginString(pStr);
      +
      8679  EndString();
      +
      8680 }
      +
      8681 
      +
      8682 void VmaJsonWriter::BeginString(const char* pStr)
      +
      8683 {
      +
      8684  VMA_ASSERT(!m_InsideString);
      +
      8685 
      +
      8686  BeginValue(true);
      +
      8687  m_SB.Add('"');
      +
      8688  m_InsideString = true;
      +
      8689  if(pStr != VMA_NULL && pStr[0] != '\0')
      +
      8690  {
      +
      8691  ContinueString(pStr);
      +
      8692  }
      +
      8693 }
      +
      8694 
      +
      8695 void VmaJsonWriter::ContinueString(const char* pStr)
      +
      8696 {
      +
      8697  VMA_ASSERT(m_InsideString);
      +
      8698 
      +
      8699  const size_t strLen = strlen(pStr);
      +
      8700  for(size_t i = 0; i < strLen; ++i)
      +
      8701  {
      +
      8702  char ch = pStr[i];
      +
      8703  if(ch == '\\')
      +
      8704  {
      +
      8705  m_SB.Add("\\\\");
      +
      8706  }
      +
      8707  else if(ch == '"')
      +
      8708  {
      +
      8709  m_SB.Add("\\\"");
      +
      8710  }
      +
      8711  else if(ch >= 32)
      +
      8712  {
      +
      8713  m_SB.Add(ch);
      +
      8714  }
      +
      8715  else switch(ch)
      +
      8716  {
      +
      8717  case '\b':
      +
      8718  m_SB.Add("\\b");
      +
      8719  break;
      +
      8720  case '\f':
      +
      8721  m_SB.Add("\\f");
      +
      8722  break;
      +
      8723  case '\n':
      +
      8724  m_SB.Add("\\n");
      +
      8725  break;
      +
      8726  case '\r':
      +
      8727  m_SB.Add("\\r");
      +
      8728  break;
      +
      8729  case '\t':
      +
      8730  m_SB.Add("\\t");
      +
      8731  break;
      +
      8732  default:
      +
      8733  VMA_ASSERT(0 && "Character not currently supported.");
      +
      8734  break;
      +
      8735  }
      +
      8736  }
      +
      8737 }
      +
      8738 
      +
      8739 void VmaJsonWriter::ContinueString(uint32_t n)
      +
      8740 {
      +
      8741  VMA_ASSERT(m_InsideString);
      +
      8742  m_SB.AddNumber(n);
      +
      8743 }
      +
      8744 
      +
      8745 void VmaJsonWriter::ContinueString(uint64_t n)
      +
      8746 {
      +
      8747  VMA_ASSERT(m_InsideString);
      +
      8748  m_SB.AddNumber(n);
      +
      8749 }
      +
      8750 
      +
      8751 void VmaJsonWriter::ContinueString_Pointer(const void* ptr)
      +
      8752 {
      +
      8753  VMA_ASSERT(m_InsideString);
      +
      8754  m_SB.AddPointer(ptr);
      +
      8755 }
      +
      8756 
      +
      8757 void VmaJsonWriter::EndString(const char* pStr)
      +
      8758 {
      +
      8759  VMA_ASSERT(m_InsideString);
      +
      8760  if(pStr != VMA_NULL && pStr[0] != '\0')
      +
      8761  {
      +
      8762  ContinueString(pStr);
      +
      8763  }
      +
      8764  m_SB.Add('"');
      +
      8765  m_InsideString = false;
      +
      8766 }
      +
      8767 
      +
      8768 void VmaJsonWriter::WriteNumber(uint32_t n)
      +
      8769 {
      +
      8770  VMA_ASSERT(!m_InsideString);
      +
      8771  BeginValue(false);
      +
      8772  m_SB.AddNumber(n);
      +
      8773 }
      +
      8774 
      +
      8775 void VmaJsonWriter::WriteNumber(uint64_t n)
      +
      8776 {
      +
      8777  VMA_ASSERT(!m_InsideString);
      +
      8778  BeginValue(false);
      +
      8779  m_SB.AddNumber(n);
      +
      8780 }
      +
      8781 
      +
      8782 void VmaJsonWriter::WriteBool(bool b)
      +
      8783 {
      +
      8784  VMA_ASSERT(!m_InsideString);
      +
      8785  BeginValue(false);
      +
      8786  m_SB.Add(b ? "true" : "false");
      +
      8787 }
      +
      8788 
      +
      8789 void VmaJsonWriter::WriteNull()
      +
      8790 {
      +
      8791  VMA_ASSERT(!m_InsideString);
      +
      8792  BeginValue(false);
      +
      8793  m_SB.Add("null");
      +
      8794 }
      +
      8795 
      +
      8796 void VmaJsonWriter::BeginValue(bool isString)
      +
      8797 {
      +
      8798  if(!m_Stack.empty())
      +
      8799  {
      +
      8800  StackItem& currItem = m_Stack.back();
      +
      8801  if(currItem.type == COLLECTION_TYPE_OBJECT &&
      +
      8802  currItem.valueCount % 2 == 0)
      +
      8803  {
      +
      8804  VMA_ASSERT(isString);
      +
      8805  }
      8806 
      -
      8807 void VmaAllocation_T::BlockAllocMap()
      -
      8808 {
      -
      8809  VMA_ASSERT(GetType() == ALLOCATION_TYPE_BLOCK);
      -
      8810 
      -
      8811  if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) < 0x7F)
      -
      8812  {
      -
      8813  ++m_MapCount;
      -
      8814  }
      -
      8815  else
      -
      8816  {
      -
      8817  VMA_ASSERT(0 && "Allocation mapped too many times simultaneously.");
      -
      8818  }
      -
      8819 }
      -
      8820 
      -
      8821 void VmaAllocation_T::BlockAllocUnmap()
      -
      8822 {
      -
      8823  VMA_ASSERT(GetType() == ALLOCATION_TYPE_BLOCK);
      +
      8807  if(currItem.type == COLLECTION_TYPE_OBJECT &&
      +
      8808  currItem.valueCount % 2 != 0)
      +
      8809  {
      +
      8810  m_SB.Add(": ");
      +
      8811  }
      +
      8812  else if(currItem.valueCount > 0)
      +
      8813  {
      +
      8814  m_SB.Add(", ");
      +
      8815  WriteIndent();
      +
      8816  }
      +
      8817  else
      +
      8818  {
      +
      8819  WriteIndent();
      +
      8820  }
      +
      8821  ++currItem.valueCount;
      +
      8822  }
      +
      8823 }
      8824 
      -
      8825  if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) != 0)
      -
      8826  {
      -
      8827  --m_MapCount;
      -
      8828  }
      -
      8829  else
      -
      8830  {
      -
      8831  VMA_ASSERT(0 && "Unmapping allocation not previously mapped.");
      -
      8832  }
      -
      8833 }
      -
      8834 
      -
      8835 VkResult VmaAllocation_T::DedicatedAllocMap(VmaAllocator hAllocator, void** ppData)
      -
      8836 {
      -
      8837  VMA_ASSERT(GetType() == ALLOCATION_TYPE_DEDICATED);
      -
      8838 
      -
      8839  if(m_MapCount != 0)
      -
      8840  {
      -
      8841  if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) < 0x7F)
      -
      8842  {
      -
      8843  VMA_ASSERT(m_DedicatedAllocation.m_pMappedData != VMA_NULL);
      -
      8844  *ppData = m_DedicatedAllocation.m_pMappedData;
      -
      8845  ++m_MapCount;
      -
      8846  return VK_SUCCESS;
      -
      8847  }
      -
      8848  else
      -
      8849  {
      -
      8850  VMA_ASSERT(0 && "Dedicated allocation mapped too many times simultaneously.");
      -
      8851  return VK_ERROR_MEMORY_MAP_FAILED;
      -
      8852  }
      -
      8853  }
      -
      8854  else
      -
      8855  {
      -
      8856  VkResult result = (*hAllocator->GetVulkanFunctions().vkMapMemory)(
      -
      8857  hAllocator->m_hDevice,
      -
      8858  m_DedicatedAllocation.m_hMemory,
      -
      8859  0, // offset
      -
      8860  VK_WHOLE_SIZE,
      -
      8861  0, // flags
      -
      8862  ppData);
      -
      8863  if(result == VK_SUCCESS)
      -
      8864  {
      -
      8865  m_DedicatedAllocation.m_pMappedData = *ppData;
      -
      8866  m_MapCount = 1;
      -
      8867  }
      -
      8868  return result;
      -
      8869  }
      -
      8870 }
      -
      8871 
      -
      8872 void VmaAllocation_T::DedicatedAllocUnmap(VmaAllocator hAllocator)
      -
      8873 {
      -
      8874  VMA_ASSERT(GetType() == ALLOCATION_TYPE_DEDICATED);
      -
      8875 
      -
      8876  if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) != 0)
      -
      8877  {
      -
      8878  --m_MapCount;
      -
      8879  if(m_MapCount == 0)
      -
      8880  {
      -
      8881  m_DedicatedAllocation.m_pMappedData = VMA_NULL;
      -
      8882  (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(
      -
      8883  hAllocator->m_hDevice,
      -
      8884  m_DedicatedAllocation.m_hMemory);
      -
      8885  }
      -
      8886  }
      -
      8887  else
      -
      8888  {
      -
      8889  VMA_ASSERT(0 && "Unmapping dedicated allocation not previously mapped.");
      -
      8890  }
      -
      8891 }
      -
      8892 
      -
      8893 #if VMA_STATS_STRING_ENABLED
      -
      8894 
      -
      8895 static void VmaPrintStatInfo(VmaJsonWriter& json, const VmaStatInfo& stat)
      -
      8896 {
      -
      8897  json.BeginObject();
      -
      8898 
      -
      8899  json.WriteString("Blocks");
      -
      8900  json.WriteNumber(stat.blockCount);
      -
      8901 
      -
      8902  json.WriteString("Allocations");
      -
      8903  json.WriteNumber(stat.allocationCount);
      -
      8904 
      -
      8905  json.WriteString("UnusedRanges");
      -
      8906  json.WriteNumber(stat.unusedRangeCount);
      +
      8825 void VmaJsonWriter::WriteIndent(bool oneLess)
      +
      8826 {
      +
      8827  if(!m_Stack.empty() && !m_Stack.back().singleLineMode)
      +
      8828  {
      +
      8829  m_SB.AddNewLine();
      +
      8830 
      +
      8831  size_t count = m_Stack.size();
      +
      8832  if(count > 0 && oneLess)
      +
      8833  {
      +
      8834  --count;
      +
      8835  }
      +
      8836  for(size_t i = 0; i < count; ++i)
      +
      8837  {
      +
      8838  m_SB.Add(INDENT);
      +
      8839  }
      +
      8840  }
      +
      8841 }
      +
      8842 
      +
      8843 #endif // #if VMA_STATS_STRING_ENABLED
      +
      8844 
      +
      8846 
      +
      8847 void VmaAllocation_T::SetUserData(VmaAllocator hAllocator, void* pUserData)
      +
      8848 {
      +
      8849  if(IsUserDataString())
      +
      8850  {
      +
      8851  VMA_ASSERT(pUserData == VMA_NULL || pUserData != m_pUserData);
      +
      8852 
      +
      8853  FreeUserDataString(hAllocator);
      +
      8854 
      +
      8855  if(pUserData != VMA_NULL)
      +
      8856  {
      +
      8857  m_pUserData = VmaCreateStringCopy(hAllocator->GetAllocationCallbacks(), (const char*)pUserData);
      +
      8858  }
      +
      8859  }
      +
      8860  else
      +
      8861  {
      +
      8862  m_pUserData = pUserData;
      +
      8863  }
      +
      8864 }
      +
      8865 
      +
      8866 void VmaAllocation_T::ChangeBlockAllocation(
      +
      8867  VmaAllocator hAllocator,
      +
      8868  VmaDeviceMemoryBlock* block,
      +
      8869  VkDeviceSize offset)
      +
      8870 {
      +
      8871  VMA_ASSERT(block != VMA_NULL);
      +
      8872  VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK);
      +
      8873 
      +
      8874  // Move mapping reference counter from old block to new block.
      +
      8875  if(block != m_BlockAllocation.m_Block)
      +
      8876  {
      +
      8877  uint32_t mapRefCount = m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP;
      +
      8878  if(IsPersistentMap())
      +
      8879  ++mapRefCount;
      +
      8880  m_BlockAllocation.m_Block->Unmap(hAllocator, mapRefCount);
      +
      8881  block->Map(hAllocator, mapRefCount, VMA_NULL);
      +
      8882  }
      +
      8883 
      +
      8884  m_BlockAllocation.m_Block = block;
      +
      8885  m_BlockAllocation.m_Offset = offset;
      +
      8886 }
      +
      8887 
      +
      8888 void VmaAllocation_T::ChangeOffset(VkDeviceSize newOffset)
      +
      8889 {
      +
      8890  VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK);
      +
      8891  m_BlockAllocation.m_Offset = newOffset;
      +
      8892 }
      +
      8893 
      +
      8894 VkDeviceSize VmaAllocation_T::GetOffset() const
      +
      8895 {
      +
      8896  switch(m_Type)
      +
      8897  {
      +
      8898  case ALLOCATION_TYPE_BLOCK:
      +
      8899  return m_BlockAllocation.m_Offset;
      +
      8900  case ALLOCATION_TYPE_DEDICATED:
      +
      8901  return 0;
      +
      8902  default:
      +
      8903  VMA_ASSERT(0);
      +
      8904  return 0;
      +
      8905  }
      +
      8906 }
      8907 
      -
      8908  json.WriteString("UsedBytes");
      -
      8909  json.WriteNumber(stat.usedBytes);
      -
      8910 
      -
      8911  json.WriteString("UnusedBytes");
      -
      8912  json.WriteNumber(stat.unusedBytes);
      -
      8913 
      -
      8914  if(stat.allocationCount > 1)
      -
      8915  {
      -
      8916  json.WriteString("AllocationSize");
      -
      8917  json.BeginObject(true);
      -
      8918  json.WriteString("Min");
      -
      8919  json.WriteNumber(stat.allocationSizeMin);
      -
      8920  json.WriteString("Avg");
      -
      8921  json.WriteNumber(stat.allocationSizeAvg);
      -
      8922  json.WriteString("Max");
      -
      8923  json.WriteNumber(stat.allocationSizeMax);
      -
      8924  json.EndObject();
      -
      8925  }
      -
      8926 
      -
      8927  if(stat.unusedRangeCount > 1)
      -
      8928  {
      -
      8929  json.WriteString("UnusedRangeSize");
      -
      8930  json.BeginObject(true);
      -
      8931  json.WriteString("Min");
      -
      8932  json.WriteNumber(stat.unusedRangeSizeMin);
      -
      8933  json.WriteString("Avg");
      -
      8934  json.WriteNumber(stat.unusedRangeSizeAvg);
      -
      8935  json.WriteString("Max");
      -
      8936  json.WriteNumber(stat.unusedRangeSizeMax);
      -
      8937  json.EndObject();
      -
      8938  }
      -
      8939 
      -
      8940  json.EndObject();
      -
      8941 }
      -
      8942 
      -
      8943 #endif // #if VMA_STATS_STRING_ENABLED
      -
      8944 
      -
      8945 struct VmaSuballocationItemSizeLess
      -
      8946 {
      -
      8947  bool operator()(
      -
      8948  const VmaSuballocationList::iterator lhs,
      -
      8949  const VmaSuballocationList::iterator rhs) const
      -
      8950  {
      -
      8951  return lhs->size < rhs->size;
      -
      8952  }
      -
      8953  bool operator()(
      -
      8954  const VmaSuballocationList::iterator lhs,
      -
      8955  VkDeviceSize rhsSize) const
      -
      8956  {
      -
      8957  return lhs->size < rhsSize;
      +
      8908 VkDeviceMemory VmaAllocation_T::GetMemory() const
      +
      8909 {
      +
      8910  switch(m_Type)
      +
      8911  {
      +
      8912  case ALLOCATION_TYPE_BLOCK:
      +
      8913  return m_BlockAllocation.m_Block->GetDeviceMemory();
      +
      8914  case ALLOCATION_TYPE_DEDICATED:
      +
      8915  return m_DedicatedAllocation.m_hMemory;
      +
      8916  default:
      +
      8917  VMA_ASSERT(0);
      +
      8918  return VK_NULL_HANDLE;
      +
      8919  }
      +
      8920 }
      +
      8921 
      +
      8922 void* VmaAllocation_T::GetMappedData() const
      +
      8923 {
      +
      8924  switch(m_Type)
      +
      8925  {
      +
      8926  case ALLOCATION_TYPE_BLOCK:
      +
      8927  if(m_MapCount != 0)
      +
      8928  {
      +
      8929  void* pBlockData = m_BlockAllocation.m_Block->GetMappedData();
      +
      8930  VMA_ASSERT(pBlockData != VMA_NULL);
      +
      8931  return (char*)pBlockData + m_BlockAllocation.m_Offset;
      +
      8932  }
      +
      8933  else
      +
      8934  {
      +
      8935  return VMA_NULL;
      +
      8936  }
      +
      8937  break;
      +
      8938  case ALLOCATION_TYPE_DEDICATED:
      +
      8939  VMA_ASSERT((m_DedicatedAllocation.m_pMappedData != VMA_NULL) == (m_MapCount != 0));
      +
      8940  return m_DedicatedAllocation.m_pMappedData;
      +
      8941  default:
      +
      8942  VMA_ASSERT(0);
      +
      8943  return VMA_NULL;
      +
      8944  }
      +
      8945 }
      +
      8946 
      +
      8947 bool VmaAllocation_T::CanBecomeLost() const
      +
      8948 {
      +
      8949  switch(m_Type)
      +
      8950  {
      +
      8951  case ALLOCATION_TYPE_BLOCK:
      +
      8952  return m_BlockAllocation.m_CanBecomeLost;
      +
      8953  case ALLOCATION_TYPE_DEDICATED:
      +
      8954  return false;
      +
      8955  default:
      +
      8956  VMA_ASSERT(0);
      +
      8957  return false;
      8958  }
      -
      8959 };
      +
      8959 }
      8960 
      -
      8961 
      -
      8963 // class VmaBlockMetadata
      +
      8961 bool VmaAllocation_T::MakeLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)
      +
      8962 {
      +
      8963  VMA_ASSERT(CanBecomeLost());
      8964 
      -
      8965 VmaBlockMetadata::VmaBlockMetadata(VmaAllocator hAllocator) :
      -
      8966  m_Size(0),
      -
      8967  m_pAllocationCallbacks(hAllocator->GetAllocationCallbacks())
      -
      8968 {
      -
      8969 }
      -
      8970 
      -
      8971 #if VMA_STATS_STRING_ENABLED
      -
      8972 
      -
      8973 void VmaBlockMetadata::PrintDetailedMap_Begin(class VmaJsonWriter& json,
      -
      8974  VkDeviceSize unusedBytes,
      -
      8975  size_t allocationCount,
      -
      8976  size_t unusedRangeCount) const
      -
      8977 {
      -
      8978  json.BeginObject();
      -
      8979 
      -
      8980  json.WriteString("TotalBytes");
      -
      8981  json.WriteNumber(GetSize());
      -
      8982 
      -
      8983  json.WriteString("UnusedBytes");
      -
      8984  json.WriteNumber(unusedBytes);
      -
      8985 
      -
      8986  json.WriteString("Allocations");
      -
      8987  json.WriteNumber((uint64_t)allocationCount);
      -
      8988 
      -
      8989  json.WriteString("UnusedRanges");
      -
      8990  json.WriteNumber((uint64_t)unusedRangeCount);
      -
      8991 
      -
      8992  json.WriteString("Suballocations");
      -
      8993  json.BeginArray();
      -
      8994 }
      -
      8995 
      -
      8996 void VmaBlockMetadata::PrintDetailedMap_Allocation(class VmaJsonWriter& json,
      -
      8997  VkDeviceSize offset,
      -
      8998  VmaAllocation hAllocation) const
      -
      8999 {
      -
      9000  json.BeginObject(true);
      -
      9001 
      -
      9002  json.WriteString("Offset");
      -
      9003  json.WriteNumber(offset);
      +
      8965  /*
      +
      8966  Warning: This is a carefully designed algorithm.
      +
      8967  Do not modify unless you really know what you're doing :)
      +
      8968  */
      +
      8969  uint32_t localLastUseFrameIndex = GetLastUseFrameIndex();
      +
      8970  for(;;)
      +
      8971  {
      +
      8972  if(localLastUseFrameIndex == VMA_FRAME_INDEX_LOST)
      +
      8973  {
      +
      8974  VMA_ASSERT(0);
      +
      8975  return false;
      +
      8976  }
      +
      8977  else if(localLastUseFrameIndex + frameInUseCount >= currentFrameIndex)
      +
      8978  {
      +
      8979  return false;
      +
      8980  }
      +
      8981  else // Last use time earlier than current time.
      +
      8982  {
      +
      8983  if(CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, VMA_FRAME_INDEX_LOST))
      +
      8984  {
      +
      8985  // Setting hAllocation.LastUseFrameIndex atomic to VMA_FRAME_INDEX_LOST is enough to mark it as LOST.
      +
      8986  // Calling code just needs to unregister this allocation in owning VmaDeviceMemoryBlock.
      +
      8987  return true;
      +
      8988  }
      +
      8989  }
      +
      8990  }
      +
      8991 }
      +
      8992 
      +
      8993 #if VMA_STATS_STRING_ENABLED
      +
      8994 
      +
      8995 // Correspond to values of enum VmaSuballocationType.
      +
      8996 static const char* VMA_SUBALLOCATION_TYPE_NAMES[] = {
      +
      8997  "FREE",
      +
      8998  "UNKNOWN",
      +
      8999  "BUFFER",
      +
      9000  "IMAGE_UNKNOWN",
      +
      9001  "IMAGE_LINEAR",
      +
      9002  "IMAGE_OPTIMAL",
      +
      9003 };
      9004 
      -
      9005  hAllocation->PrintParameters(json);
      -
      9006 
      -
      9007  json.EndObject();
      -
      9008 }
      +
      9005 void VmaAllocation_T::PrintParameters(class VmaJsonWriter& json) const
      +
      9006 {
      +
      9007  json.WriteString("Type");
      +
      9008  json.WriteString(VMA_SUBALLOCATION_TYPE_NAMES[m_SuballocationType]);
      9009 
      -
      9010 void VmaBlockMetadata::PrintDetailedMap_UnusedRange(class VmaJsonWriter& json,
      -
      9011  VkDeviceSize offset,
      -
      9012  VkDeviceSize size) const
      -
      9013 {
      -
      9014  json.BeginObject(true);
      -
      9015 
      -
      9016  json.WriteString("Offset");
      -
      9017  json.WriteNumber(offset);
      -
      9018 
      -
      9019  json.WriteString("Type");
      -
      9020  json.WriteString(VMA_SUBALLOCATION_TYPE_NAMES[VMA_SUBALLOCATION_TYPE_FREE]);
      -
      9021 
      -
      9022  json.WriteString("Size");
      -
      9023  json.WriteNumber(size);
      -
      9024 
      -
      9025  json.EndObject();
      -
      9026 }
      +
      9010  json.WriteString("Size");
      +
      9011  json.WriteNumber(m_Size);
      +
      9012 
      +
      9013  if(m_pUserData != VMA_NULL)
      +
      9014  {
      +
      9015  json.WriteString("UserData");
      +
      9016  if(IsUserDataString())
      +
      9017  {
      +
      9018  json.WriteString((const char*)m_pUserData);
      +
      9019  }
      +
      9020  else
      +
      9021  {
      +
      9022  json.BeginString();
      +
      9023  json.ContinueString_Pointer(m_pUserData);
      +
      9024  json.EndString();
      +
      9025  }
      +
      9026  }
      9027 
      -
      9028 void VmaBlockMetadata::PrintDetailedMap_End(class VmaJsonWriter& json) const
      -
      9029 {
      -
      9030  json.EndArray();
      -
      9031  json.EndObject();
      -
      9032 }
      +
      9028  json.WriteString("CreationFrameIndex");
      +
      9029  json.WriteNumber(m_CreationFrameIndex);
      +
      9030 
      +
      9031  json.WriteString("LastUseFrameIndex");
      +
      9032  json.WriteNumber(GetLastUseFrameIndex());
      9033 
      -
      9034 #endif // #if VMA_STATS_STRING_ENABLED
      -
      9035 
      -
      9037 // class VmaBlockMetadata_Generic
      -
      9038 
      -
      9039 VmaBlockMetadata_Generic::VmaBlockMetadata_Generic(VmaAllocator hAllocator) :
      -
      9040  VmaBlockMetadata(hAllocator),
      -
      9041  m_FreeCount(0),
      -
      9042  m_SumFreeSize(0),
      -
      9043  m_Suballocations(VmaStlAllocator<VmaSuballocation>(hAllocator->GetAllocationCallbacks())),
      -
      9044  m_FreeSuballocationsBySize(VmaStlAllocator<VmaSuballocationList::iterator>(hAllocator->GetAllocationCallbacks()))
      -
      9045 {
      -
      9046 }
      -
      9047 
      -
      9048 VmaBlockMetadata_Generic::~VmaBlockMetadata_Generic()
      -
      9049 {
      -
      9050 }
      -
      9051 
      -
      9052 void VmaBlockMetadata_Generic::Init(VkDeviceSize size)
      -
      9053 {
      -
      9054  VmaBlockMetadata::Init(size);
      -
      9055 
      -
      9056  m_FreeCount = 1;
      -
      9057  m_SumFreeSize = size;
      -
      9058 
      -
      9059  VmaSuballocation suballoc = {};
      -
      9060  suballoc.offset = 0;
      -
      9061  suballoc.size = size;
      -
      9062  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
      -
      9063  suballoc.hAllocation = VK_NULL_HANDLE;
      -
      9064 
      -
      9065  VMA_ASSERT(size > VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER);
      -
      9066  m_Suballocations.push_back(suballoc);
      -
      9067  VmaSuballocationList::iterator suballocItem = m_Suballocations.end();
      -
      9068  --suballocItem;
      -
      9069  m_FreeSuballocationsBySize.push_back(suballocItem);
      -
      9070 }
      -
      9071 
      -
      9072 bool VmaBlockMetadata_Generic::Validate() const
      -
      9073 {
      -
      9074  VMA_VALIDATE(!m_Suballocations.empty());
      -
      9075 
      -
      9076  // Expected offset of new suballocation as calculated from previous ones.
      -
      9077  VkDeviceSize calculatedOffset = 0;
      -
      9078  // Expected number of free suballocations as calculated from traversing their list.
      -
      9079  uint32_t calculatedFreeCount = 0;
      -
      9080  // Expected sum size of free suballocations as calculated from traversing their list.
      -
      9081  VkDeviceSize calculatedSumFreeSize = 0;
      -
      9082  // Expected number of free suballocations that should be registered in
      -
      9083  // m_FreeSuballocationsBySize calculated from traversing their list.
      -
      9084  size_t freeSuballocationsToRegister = 0;
      -
      9085  // True if previous visited suballocation was free.
      -
      9086  bool prevFree = false;
      -
      9087 
      -
      9088  for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin();
      -
      9089  suballocItem != m_Suballocations.cend();
      -
      9090  ++suballocItem)
      -
      9091  {
      -
      9092  const VmaSuballocation& subAlloc = *suballocItem;
      -
      9093 
      -
      9094  // Actual offset of this suballocation doesn't match expected one.
      -
      9095  VMA_VALIDATE(subAlloc.offset == calculatedOffset);
      -
      9096 
      -
      9097  const bool currFree = (subAlloc.type == VMA_SUBALLOCATION_TYPE_FREE);
      -
      9098  // Two adjacent free suballocations are invalid. They should be merged.
      -
      9099  VMA_VALIDATE(!prevFree || !currFree);
      -
      9100 
      -
      9101  VMA_VALIDATE(currFree == (subAlloc.hAllocation == VK_NULL_HANDLE));
      -
      9102 
      -
      9103  if(currFree)
      -
      9104  {
      -
      9105  calculatedSumFreeSize += subAlloc.size;
      -
      9106  ++calculatedFreeCount;
      -
      9107  if(subAlloc.size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
      -
      9108  {
      -
      9109  ++freeSuballocationsToRegister;
      -
      9110  }
      -
      9111 
      -
      9112  // Margin required between allocations - every free space must be at least that large.
      -
      9113  VMA_VALIDATE(subAlloc.size >= VMA_DEBUG_MARGIN);
      -
      9114  }
      -
      9115  else
      -
      9116  {
      -
      9117  VMA_VALIDATE(subAlloc.hAllocation->GetOffset() == subAlloc.offset);
      -
      9118  VMA_VALIDATE(subAlloc.hAllocation->GetSize() == subAlloc.size);
      -
      9119 
      -
      9120  // Margin required between allocations - previous allocation must be free.
      -
      9121  VMA_VALIDATE(VMA_DEBUG_MARGIN == 0 || prevFree);
      -
      9122  }
      -
      9123 
      -
      9124  calculatedOffset += subAlloc.size;
      -
      9125  prevFree = currFree;
      -
      9126  }
      -
      9127 
      -
      9128  // Number of free suballocations registered in m_FreeSuballocationsBySize doesn't
      -
      9129  // match expected one.
      -
      9130  VMA_VALIDATE(m_FreeSuballocationsBySize.size() == freeSuballocationsToRegister);
      -
      9131 
      -
      9132  VkDeviceSize lastSize = 0;
      -
      9133  for(size_t i = 0; i < m_FreeSuballocationsBySize.size(); ++i)
      -
      9134  {
      -
      9135  VmaSuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[i];
      -
      9136 
      -
      9137  // Only free suballocations can be registered in m_FreeSuballocationsBySize.
      -
      9138  VMA_VALIDATE(suballocItem->type == VMA_SUBALLOCATION_TYPE_FREE);
      -
      9139  // They must be sorted by size ascending.
      -
      9140  VMA_VALIDATE(suballocItem->size >= lastSize);
      +
      9034  if(m_BufferImageUsage != 0)
      +
      9035  {
      +
      9036  json.WriteString("Usage");
      +
      9037  json.WriteNumber(m_BufferImageUsage);
      +
      9038  }
      +
      9039 }
      +
      9040 
      +
      9041 #endif
      +
      9042 
      +
      9043 void VmaAllocation_T::FreeUserDataString(VmaAllocator hAllocator)
      +
      9044 {
      +
      9045  VMA_ASSERT(IsUserDataString());
      +
      9046  VmaFreeString(hAllocator->GetAllocationCallbacks(), (char*)m_pUserData);
      +
      9047  m_pUserData = VMA_NULL;
      +
      9048 }
      +
      9049 
      +
      9050 void VmaAllocation_T::BlockAllocMap()
      +
      9051 {
      +
      9052  VMA_ASSERT(GetType() == ALLOCATION_TYPE_BLOCK);
      +
      9053 
      +
      9054  if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) < 0x7F)
      +
      9055  {
      +
      9056  ++m_MapCount;
      +
      9057  }
      +
      9058  else
      +
      9059  {
      +
      9060  VMA_ASSERT(0 && "Allocation mapped too many times simultaneously.");
      +
      9061  }
      +
      9062 }
      +
      9063 
      +
      9064 void VmaAllocation_T::BlockAllocUnmap()
      +
      9065 {
      +
      9066  VMA_ASSERT(GetType() == ALLOCATION_TYPE_BLOCK);
      +
      9067 
      +
      9068  if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) != 0)
      +
      9069  {
      +
      9070  --m_MapCount;
      +
      9071  }
      +
      9072  else
      +
      9073  {
      +
      9074  VMA_ASSERT(0 && "Unmapping allocation not previously mapped.");
      +
      9075  }
      +
      9076 }
      +
      9077 
      +
      9078 VkResult VmaAllocation_T::DedicatedAllocMap(VmaAllocator hAllocator, void** ppData)
      +
      9079 {
      +
      9080  VMA_ASSERT(GetType() == ALLOCATION_TYPE_DEDICATED);
      +
      9081 
      +
      9082  if(m_MapCount != 0)
      +
      9083  {
      +
      9084  if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) < 0x7F)
      +
      9085  {
      +
      9086  VMA_ASSERT(m_DedicatedAllocation.m_pMappedData != VMA_NULL);
      +
      9087  *ppData = m_DedicatedAllocation.m_pMappedData;
      +
      9088  ++m_MapCount;
      +
      9089  return VK_SUCCESS;
      +
      9090  }
      +
      9091  else
      +
      9092  {
      +
      9093  VMA_ASSERT(0 && "Dedicated allocation mapped too many times simultaneously.");
      +
      9094  return VK_ERROR_MEMORY_MAP_FAILED;
      +
      9095  }
      +
      9096  }
      +
      9097  else
      +
      9098  {
      +
      9099  VkResult result = (*hAllocator->GetVulkanFunctions().vkMapMemory)(
      +
      9100  hAllocator->m_hDevice,
      +
      9101  m_DedicatedAllocation.m_hMemory,
      +
      9102  0, // offset
      +
      9103  VK_WHOLE_SIZE,
      +
      9104  0, // flags
      +
      9105  ppData);
      +
      9106  if(result == VK_SUCCESS)
      +
      9107  {
      +
      9108  m_DedicatedAllocation.m_pMappedData = *ppData;
      +
      9109  m_MapCount = 1;
      +
      9110  }
      +
      9111  return result;
      +
      9112  }
      +
      9113 }
      +
      9114 
      +
      9115 void VmaAllocation_T::DedicatedAllocUnmap(VmaAllocator hAllocator)
      +
      9116 {
      +
      9117  VMA_ASSERT(GetType() == ALLOCATION_TYPE_DEDICATED);
      +
      9118 
      +
      9119  if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) != 0)
      +
      9120  {
      +
      9121  --m_MapCount;
      +
      9122  if(m_MapCount == 0)
      +
      9123  {
      +
      9124  m_DedicatedAllocation.m_pMappedData = VMA_NULL;
      +
      9125  (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(
      +
      9126  hAllocator->m_hDevice,
      +
      9127  m_DedicatedAllocation.m_hMemory);
      +
      9128  }
      +
      9129  }
      +
      9130  else
      +
      9131  {
      +
      9132  VMA_ASSERT(0 && "Unmapping dedicated allocation not previously mapped.");
      +
      9133  }
      +
      9134 }
      +
      9135 
      +
      9136 #if VMA_STATS_STRING_ENABLED
      +
      9137 
      +
      9138 static void VmaPrintStatInfo(VmaJsonWriter& json, const VmaStatInfo& stat)
      +
      9139 {
      +
      9140  json.BeginObject();
      9141 
      -
      9142  lastSize = suballocItem->size;
      -
      9143  }
      +
      9142  json.WriteString("Blocks");
      +
      9143  json.WriteNumber(stat.blockCount);
      9144 
      -
      9145  // Check if totals match calculacted values.
      -
      9146  VMA_VALIDATE(ValidateFreeSuballocationList());
      -
      9147  VMA_VALIDATE(calculatedOffset == GetSize());
      -
      9148  VMA_VALIDATE(calculatedSumFreeSize == m_SumFreeSize);
      -
      9149  VMA_VALIDATE(calculatedFreeCount == m_FreeCount);
      +
      9145  json.WriteString("Allocations");
      +
      9146  json.WriteNumber(stat.allocationCount);
      +
      9147 
      +
      9148  json.WriteString("UnusedRanges");
      +
      9149  json.WriteNumber(stat.unusedRangeCount);
      9150 
      -
      9151  return true;
      -
      9152 }
      +
      9151  json.WriteString("UsedBytes");
      +
      9152  json.WriteNumber(stat.usedBytes);
      9153 
      -
      9154 VkDeviceSize VmaBlockMetadata_Generic::GetUnusedRangeSizeMax() const
      -
      9155 {
      -
      9156  if(!m_FreeSuballocationsBySize.empty())
      -
      9157  {
      -
      9158  return m_FreeSuballocationsBySize.back()->size;
      -
      9159  }
      -
      9160  else
      -
      9161  {
      -
      9162  return 0;
      -
      9163  }
      -
      9164 }
      -
      9165 
      -
      9166 bool VmaBlockMetadata_Generic::IsEmpty() const
      -
      9167 {
      -
      9168  return (m_Suballocations.size() == 1) && (m_FreeCount == 1);
      -
      9169 }
      -
      9170 
      -
      9171 void VmaBlockMetadata_Generic::CalcAllocationStatInfo(VmaStatInfo& outInfo) const
      -
      9172 {
      -
      9173  outInfo.blockCount = 1;
      -
      9174 
      -
      9175  const uint32_t rangeCount = (uint32_t)m_Suballocations.size();
      -
      9176  outInfo.allocationCount = rangeCount - m_FreeCount;
      -
      9177  outInfo.unusedRangeCount = m_FreeCount;
      -
      9178 
      -
      9179  outInfo.unusedBytes = m_SumFreeSize;
      -
      9180  outInfo.usedBytes = GetSize() - outInfo.unusedBytes;
      -
      9181 
      -
      9182  outInfo.allocationSizeMin = UINT64_MAX;
      -
      9183  outInfo.allocationSizeMax = 0;
      -
      9184  outInfo.unusedRangeSizeMin = UINT64_MAX;
      -
      9185  outInfo.unusedRangeSizeMax = 0;
      -
      9186 
      -
      9187  for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin();
      -
      9188  suballocItem != m_Suballocations.cend();
      -
      9189  ++suballocItem)
      -
      9190  {
      -
      9191  const VmaSuballocation& suballoc = *suballocItem;
      -
      9192  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
      -
      9193  {
      -
      9194  outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size);
      -
      9195  outInfo.allocationSizeMax = VMA_MAX(outInfo.allocationSizeMax, suballoc.size);
      -
      9196  }
      -
      9197  else
      -
      9198  {
      -
      9199  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, suballoc.size);
      -
      9200  outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, suballoc.size);
      -
      9201  }
      -
      9202  }
      -
      9203 }
      +
      9154  json.WriteString("UnusedBytes");
      +
      9155  json.WriteNumber(stat.unusedBytes);
      +
      9156 
      +
      9157  if(stat.allocationCount > 1)
      +
      9158  {
      +
      9159  json.WriteString("AllocationSize");
      +
      9160  json.BeginObject(true);
      +
      9161  json.WriteString("Min");
      +
      9162  json.WriteNumber(stat.allocationSizeMin);
      +
      9163  json.WriteString("Avg");
      +
      9164  json.WriteNumber(stat.allocationSizeAvg);
      +
      9165  json.WriteString("Max");
      +
      9166  json.WriteNumber(stat.allocationSizeMax);
      +
      9167  json.EndObject();
      +
      9168  }
      +
      9169 
      +
      9170  if(stat.unusedRangeCount > 1)
      +
      9171  {
      +
      9172  json.WriteString("UnusedRangeSize");
      +
      9173  json.BeginObject(true);
      +
      9174  json.WriteString("Min");
      +
      9175  json.WriteNumber(stat.unusedRangeSizeMin);
      +
      9176  json.WriteString("Avg");
      +
      9177  json.WriteNumber(stat.unusedRangeSizeAvg);
      +
      9178  json.WriteString("Max");
      +
      9179  json.WriteNumber(stat.unusedRangeSizeMax);
      +
      9180  json.EndObject();
      +
      9181  }
      +
      9182 
      +
      9183  json.EndObject();
      +
      9184 }
      +
      9185 
      +
      9186 #endif // #if VMA_STATS_STRING_ENABLED
      +
      9187 
      +
      9188 struct VmaSuballocationItemSizeLess
      +
      9189 {
      +
      9190  bool operator()(
      +
      9191  const VmaSuballocationList::iterator lhs,
      +
      9192  const VmaSuballocationList::iterator rhs) const
      +
      9193  {
      +
      9194  return lhs->size < rhs->size;
      +
      9195  }
      +
      9196  bool operator()(
      +
      9197  const VmaSuballocationList::iterator lhs,
      +
      9198  VkDeviceSize rhsSize) const
      +
      9199  {
      +
      9200  return lhs->size < rhsSize;
      +
      9201  }
      +
      9202 };
      +
      9203 
      9204 
      -
      9205 void VmaBlockMetadata_Generic::AddPoolStats(VmaPoolStats& inoutStats) const
      -
      9206 {
      -
      9207  const uint32_t rangeCount = (uint32_t)m_Suballocations.size();
      -
      9208 
      -
      9209  inoutStats.size += GetSize();
      -
      9210  inoutStats.unusedSize += m_SumFreeSize;
      -
      9211  inoutStats.allocationCount += rangeCount - m_FreeCount;
      -
      9212  inoutStats.unusedRangeCount += m_FreeCount;
      -
      9213  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, GetUnusedRangeSizeMax());
      -
      9214 }
      +
      9206 // class VmaBlockMetadata
      +
      9207 
      +
      9208 VmaBlockMetadata::VmaBlockMetadata(VmaAllocator hAllocator) :
      +
      9209  m_Size(0),
      +
      9210  m_pAllocationCallbacks(hAllocator->GetAllocationCallbacks())
      +
      9211 {
      +
      9212 }
      +
      9213 
      +
      9214 #if VMA_STATS_STRING_ENABLED
      9215 
      -
      9216 #if VMA_STATS_STRING_ENABLED
      -
      9217 
      -
      9218 void VmaBlockMetadata_Generic::PrintDetailedMap(class VmaJsonWriter& json) const
      -
      9219 {
      -
      9220  PrintDetailedMap_Begin(json,
      -
      9221  m_SumFreeSize, // unusedBytes
      -
      9222  m_Suballocations.size() - (size_t)m_FreeCount, // allocationCount
      -
      9223  m_FreeCount); // unusedRangeCount
      -
      9224 
      -
      9225  size_t i = 0;
      -
      9226  for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin();
      -
      9227  suballocItem != m_Suballocations.cend();
      -
      9228  ++suballocItem, ++i)
      -
      9229  {
      -
      9230  if(suballocItem->type == VMA_SUBALLOCATION_TYPE_FREE)
      -
      9231  {
      -
      9232  PrintDetailedMap_UnusedRange(json, suballocItem->offset, suballocItem->size);
      -
      9233  }
      -
      9234  else
      -
      9235  {
      -
      9236  PrintDetailedMap_Allocation(json, suballocItem->offset, suballocItem->hAllocation);
      -
      9237  }
      -
      9238  }
      -
      9239 
      -
      9240  PrintDetailedMap_End(json);
      -
      9241 }
      -
      9242 
      -
      9243 #endif // #if VMA_STATS_STRING_ENABLED
      +
      9216 void VmaBlockMetadata::PrintDetailedMap_Begin(class VmaJsonWriter& json,
      +
      9217  VkDeviceSize unusedBytes,
      +
      9218  size_t allocationCount,
      +
      9219  size_t unusedRangeCount) const
      +
      9220 {
      +
      9221  json.BeginObject();
      +
      9222 
      +
      9223  json.WriteString("TotalBytes");
      +
      9224  json.WriteNumber(GetSize());
      +
      9225 
      +
      9226  json.WriteString("UnusedBytes");
      +
      9227  json.WriteNumber(unusedBytes);
      +
      9228 
      +
      9229  json.WriteString("Allocations");
      +
      9230  json.WriteNumber((uint64_t)allocationCount);
      +
      9231 
      +
      9232  json.WriteString("UnusedRanges");
      +
      9233  json.WriteNumber((uint64_t)unusedRangeCount);
      +
      9234 
      +
      9235  json.WriteString("Suballocations");
      +
      9236  json.BeginArray();
      +
      9237 }
      +
      9238 
      +
      9239 void VmaBlockMetadata::PrintDetailedMap_Allocation(class VmaJsonWriter& json,
      +
      9240  VkDeviceSize offset,
      +
      9241  VmaAllocation hAllocation) const
      +
      9242 {
      +
      9243  json.BeginObject(true);
      9244 
      -
      9245 bool VmaBlockMetadata_Generic::CreateAllocationRequest(
      -
      9246  uint32_t currentFrameIndex,
      -
      9247  uint32_t frameInUseCount,
      -
      9248  VkDeviceSize bufferImageGranularity,
      -
      9249  VkDeviceSize allocSize,
      -
      9250  VkDeviceSize allocAlignment,
      -
      9251  bool upperAddress,
      -
      9252  VmaSuballocationType allocType,
      -
      9253  bool canMakeOtherLost,
      -
      9254  uint32_t strategy,
      -
      9255  VmaAllocationRequest* pAllocationRequest)
      -
      9256 {
      -
      9257  VMA_ASSERT(allocSize > 0);
      -
      9258  VMA_ASSERT(!upperAddress);
      -
      9259  VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE);
      -
      9260  VMA_ASSERT(pAllocationRequest != VMA_NULL);
      -
      9261  VMA_HEAVY_ASSERT(Validate());
      -
      9262 
      -
      9263  pAllocationRequest->type = VmaAllocationRequestType::Normal;
      +
      9245  json.WriteString("Offset");
      +
      9246  json.WriteNumber(offset);
      +
      9247 
      +
      9248  hAllocation->PrintParameters(json);
      +
      9249 
      +
      9250  json.EndObject();
      +
      9251 }
      +
      9252 
      +
      9253 void VmaBlockMetadata::PrintDetailedMap_UnusedRange(class VmaJsonWriter& json,
      +
      9254  VkDeviceSize offset,
      +
      9255  VkDeviceSize size) const
      +
      9256 {
      +
      9257  json.BeginObject(true);
      +
      9258 
      +
      9259  json.WriteString("Offset");
      +
      9260  json.WriteNumber(offset);
      +
      9261 
      +
      9262  json.WriteString("Type");
      +
      9263  json.WriteString(VMA_SUBALLOCATION_TYPE_NAMES[VMA_SUBALLOCATION_TYPE_FREE]);
      9264 
      -
      9265  // There is not enough total free space in this block to fullfill the request: Early return.
      -
      9266  if(canMakeOtherLost == false &&
      -
      9267  m_SumFreeSize < allocSize + 2 * VMA_DEBUG_MARGIN)
      -
      9268  {
      -
      9269  return false;
      -
      9270  }
      -
      9271 
      -
      9272  // New algorithm, efficiently searching freeSuballocationsBySize.
      -
      9273  const size_t freeSuballocCount = m_FreeSuballocationsBySize.size();
      -
      9274  if(freeSuballocCount > 0)
      -
      9275  {
      - -
      9277  {
      -
      9278  // Find first free suballocation with size not less than allocSize + 2 * VMA_DEBUG_MARGIN.
      -
      9279  VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess(
      -
      9280  m_FreeSuballocationsBySize.data(),
      -
      9281  m_FreeSuballocationsBySize.data() + freeSuballocCount,
      -
      9282  allocSize + 2 * VMA_DEBUG_MARGIN,
      -
      9283  VmaSuballocationItemSizeLess());
      -
      9284  size_t index = it - m_FreeSuballocationsBySize.data();
      -
      9285  for(; index < freeSuballocCount; ++index)
      -
      9286  {
      -
      9287  if(CheckAllocation(
      -
      9288  currentFrameIndex,
      -
      9289  frameInUseCount,
      -
      9290  bufferImageGranularity,
      -
      9291  allocSize,
      -
      9292  allocAlignment,
      -
      9293  allocType,
      -
      9294  m_FreeSuballocationsBySize[index],
      -
      9295  false, // canMakeOtherLost
      -
      9296  &pAllocationRequest->offset,
      -
      9297  &pAllocationRequest->itemsToMakeLostCount,
      -
      9298  &pAllocationRequest->sumFreeSize,
      -
      9299  &pAllocationRequest->sumItemSize))
      -
      9300  {
      -
      9301  pAllocationRequest->item = m_FreeSuballocationsBySize[index];
      -
      9302  return true;
      -
      9303  }
      -
      9304  }
      -
      9305  }
      -
      9306  else if(strategy == VMA_ALLOCATION_INTERNAL_STRATEGY_MIN_OFFSET)
      -
      9307  {
      -
      9308  for(VmaSuballocationList::iterator it = m_Suballocations.begin();
      -
      9309  it != m_Suballocations.end();
      -
      9310  ++it)
      -
      9311  {
      -
      9312  if(it->type == VMA_SUBALLOCATION_TYPE_FREE && CheckAllocation(
      -
      9313  currentFrameIndex,
      -
      9314  frameInUseCount,
      -
      9315  bufferImageGranularity,
      -
      9316  allocSize,
      -
      9317  allocAlignment,
      -
      9318  allocType,
      -
      9319  it,
      -
      9320  false, // canMakeOtherLost
      -
      9321  &pAllocationRequest->offset,
      -
      9322  &pAllocationRequest->itemsToMakeLostCount,
      -
      9323  &pAllocationRequest->sumFreeSize,
      -
      9324  &pAllocationRequest->sumItemSize))
      -
      9325  {
      -
      9326  pAllocationRequest->item = it;
      -
      9327  return true;
      -
      9328  }
      -
      9329  }
      -
      9330  }
      -
      9331  else // WORST_FIT, FIRST_FIT
      -
      9332  {
      -
      9333  // Search staring from biggest suballocations.
      -
      9334  for(size_t index = freeSuballocCount; index--; )
      -
      9335  {
      -
      9336  if(CheckAllocation(
      -
      9337  currentFrameIndex,
      -
      9338  frameInUseCount,
      -
      9339  bufferImageGranularity,
      -
      9340  allocSize,
      -
      9341  allocAlignment,
      -
      9342  allocType,
      -
      9343  m_FreeSuballocationsBySize[index],
      -
      9344  false, // canMakeOtherLost
      -
      9345  &pAllocationRequest->offset,
      -
      9346  &pAllocationRequest->itemsToMakeLostCount,
      -
      9347  &pAllocationRequest->sumFreeSize,
      -
      9348  &pAllocationRequest->sumItemSize))
      -
      9349  {
      -
      9350  pAllocationRequest->item = m_FreeSuballocationsBySize[index];
      -
      9351  return true;
      -
      9352  }
      +
      9265  json.WriteString("Size");
      +
      9266  json.WriteNumber(size);
      +
      9267 
      +
      9268  json.EndObject();
      +
      9269 }
      +
      9270 
      +
      9271 void VmaBlockMetadata::PrintDetailedMap_End(class VmaJsonWriter& json) const
      +
      9272 {
      +
      9273  json.EndArray();
      +
      9274  json.EndObject();
      +
      9275 }
      +
      9276 
      +
      9277 #endif // #if VMA_STATS_STRING_ENABLED
      +
      9278 
      +
      9280 // class VmaBlockMetadata_Generic
      +
      9281 
      +
      9282 VmaBlockMetadata_Generic::VmaBlockMetadata_Generic(VmaAllocator hAllocator) :
      +
      9283  VmaBlockMetadata(hAllocator),
      +
      9284  m_FreeCount(0),
      +
      9285  m_SumFreeSize(0),
      +
      9286  m_Suballocations(VmaStlAllocator<VmaSuballocation>(hAllocator->GetAllocationCallbacks())),
      +
      9287  m_FreeSuballocationsBySize(VmaStlAllocator<VmaSuballocationList::iterator>(hAllocator->GetAllocationCallbacks()))
      +
      9288 {
      +
      9289 }
      +
      9290 
      +
      9291 VmaBlockMetadata_Generic::~VmaBlockMetadata_Generic()
      +
      9292 {
      +
      9293 }
      +
      9294 
      +
      9295 void VmaBlockMetadata_Generic::Init(VkDeviceSize size)
      +
      9296 {
      +
      9297  VmaBlockMetadata::Init(size);
      +
      9298 
      +
      9299  m_FreeCount = 1;
      +
      9300  m_SumFreeSize = size;
      +
      9301 
      +
      9302  VmaSuballocation suballoc = {};
      +
      9303  suballoc.offset = 0;
      +
      9304  suballoc.size = size;
      +
      9305  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
      +
      9306  suballoc.hAllocation = VK_NULL_HANDLE;
      +
      9307 
      +
      9308  VMA_ASSERT(size > VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER);
      +
      9309  m_Suballocations.push_back(suballoc);
      +
      9310  VmaSuballocationList::iterator suballocItem = m_Suballocations.end();
      +
      9311  --suballocItem;
      +
      9312  m_FreeSuballocationsBySize.push_back(suballocItem);
      +
      9313 }
      +
      9314 
      +
      9315 bool VmaBlockMetadata_Generic::Validate() const
      +
      9316 {
      +
      9317  VMA_VALIDATE(!m_Suballocations.empty());
      +
      9318 
      +
      9319  // Expected offset of new suballocation as calculated from previous ones.
      +
      9320  VkDeviceSize calculatedOffset = 0;
      +
      9321  // Expected number of free suballocations as calculated from traversing their list.
      +
      9322  uint32_t calculatedFreeCount = 0;
      +
      9323  // Expected sum size of free suballocations as calculated from traversing their list.
      +
      9324  VkDeviceSize calculatedSumFreeSize = 0;
      +
      9325  // Expected number of free suballocations that should be registered in
      +
      9326  // m_FreeSuballocationsBySize calculated from traversing their list.
      +
      9327  size_t freeSuballocationsToRegister = 0;
      +
      9328  // True if previous visited suballocation was free.
      +
      9329  bool prevFree = false;
      +
      9330 
      +
      9331  for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin();
      +
      9332  suballocItem != m_Suballocations.cend();
      +
      9333  ++suballocItem)
      +
      9334  {
      +
      9335  const VmaSuballocation& subAlloc = *suballocItem;
      +
      9336 
      +
      9337  // Actual offset of this suballocation doesn't match expected one.
      +
      9338  VMA_VALIDATE(subAlloc.offset == calculatedOffset);
      +
      9339 
      +
      9340  const bool currFree = (subAlloc.type == VMA_SUBALLOCATION_TYPE_FREE);
      +
      9341  // Two adjacent free suballocations are invalid. They should be merged.
      +
      9342  VMA_VALIDATE(!prevFree || !currFree);
      +
      9343 
      +
      9344  VMA_VALIDATE(currFree == (subAlloc.hAllocation == VK_NULL_HANDLE));
      +
      9345 
      +
      9346  if(currFree)
      +
      9347  {
      +
      9348  calculatedSumFreeSize += subAlloc.size;
      +
      9349  ++calculatedFreeCount;
      +
      9350  if(subAlloc.size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
      +
      9351  {
      +
      9352  ++freeSuballocationsToRegister;
      9353  }
      -
      9354  }
      -
      9355  }
      -
      9356 
      -
      9357  if(canMakeOtherLost)
      -
      9358  {
      -
      9359  // Brute-force algorithm. TODO: Come up with something better.
      -
      9360 
      -
      9361  bool found = false;
      -
      9362  VmaAllocationRequest tmpAllocRequest = {};
      -
      9363  tmpAllocRequest.type = VmaAllocationRequestType::Normal;
      -
      9364  for(VmaSuballocationList::iterator suballocIt = m_Suballocations.begin();
      -
      9365  suballocIt != m_Suballocations.end();
      -
      9366  ++suballocIt)
      -
      9367  {
      -
      9368  if(suballocIt->type == VMA_SUBALLOCATION_TYPE_FREE ||
      -
      9369  suballocIt->hAllocation->CanBecomeLost())
      -
      9370  {
      -
      9371  if(CheckAllocation(
      -
      9372  currentFrameIndex,
      -
      9373  frameInUseCount,
      -
      9374  bufferImageGranularity,
      -
      9375  allocSize,
      -
      9376  allocAlignment,
      -
      9377  allocType,
      -
      9378  suballocIt,
      -
      9379  canMakeOtherLost,
      -
      9380  &tmpAllocRequest.offset,
      -
      9381  &tmpAllocRequest.itemsToMakeLostCount,
      -
      9382  &tmpAllocRequest.sumFreeSize,
      -
      9383  &tmpAllocRequest.sumItemSize))
      -
      9384  {
      - -
      9386  {
      -
      9387  *pAllocationRequest = tmpAllocRequest;
      -
      9388  pAllocationRequest->item = suballocIt;
      -
      9389  break;
      -
      9390  }
      -
      9391  if(!found || tmpAllocRequest.CalcCost() < pAllocationRequest->CalcCost())
      -
      9392  {
      -
      9393  *pAllocationRequest = tmpAllocRequest;
      -
      9394  pAllocationRequest->item = suballocIt;
      -
      9395  found = true;
      -
      9396  }
      -
      9397  }
      -
      9398  }
      -
      9399  }
      -
      9400 
      -
      9401  return found;
      +
      9354 
      +
      9355  // Margin required between allocations - every free space must be at least that large.
      +
      9356  VMA_VALIDATE(subAlloc.size >= VMA_DEBUG_MARGIN);
      +
      9357  }
      +
      9358  else
      +
      9359  {
      +
      9360  VMA_VALIDATE(subAlloc.hAllocation->GetOffset() == subAlloc.offset);
      +
      9361  VMA_VALIDATE(subAlloc.hAllocation->GetSize() == subAlloc.size);
      +
      9362 
      +
      9363  // Margin required between allocations - previous allocation must be free.
      +
      9364  VMA_VALIDATE(VMA_DEBUG_MARGIN == 0 || prevFree);
      +
      9365  }
      +
      9366 
      +
      9367  calculatedOffset += subAlloc.size;
      +
      9368  prevFree = currFree;
      +
      9369  }
      +
      9370 
      +
      9371  // Number of free suballocations registered in m_FreeSuballocationsBySize doesn't
      +
      9372  // match expected one.
      +
      9373  VMA_VALIDATE(m_FreeSuballocationsBySize.size() == freeSuballocationsToRegister);
      +
      9374 
      +
      9375  VkDeviceSize lastSize = 0;
      +
      9376  for(size_t i = 0; i < m_FreeSuballocationsBySize.size(); ++i)
      +
      9377  {
      +
      9378  VmaSuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[i];
      +
      9379 
      +
      9380  // Only free suballocations can be registered in m_FreeSuballocationsBySize.
      +
      9381  VMA_VALIDATE(suballocItem->type == VMA_SUBALLOCATION_TYPE_FREE);
      +
      9382  // They must be sorted by size ascending.
      +
      9383  VMA_VALIDATE(suballocItem->size >= lastSize);
      +
      9384 
      +
      9385  lastSize = suballocItem->size;
      +
      9386  }
      +
      9387 
      +
      9388  // Check if totals match calculacted values.
      +
      9389  VMA_VALIDATE(ValidateFreeSuballocationList());
      +
      9390  VMA_VALIDATE(calculatedOffset == GetSize());
      +
      9391  VMA_VALIDATE(calculatedSumFreeSize == m_SumFreeSize);
      +
      9392  VMA_VALIDATE(calculatedFreeCount == m_FreeCount);
      +
      9393 
      +
      9394  return true;
      +
      9395 }
      +
      9396 
      +
      9397 VkDeviceSize VmaBlockMetadata_Generic::GetUnusedRangeSizeMax() const
      +
      9398 {
      +
      9399  if(!m_FreeSuballocationsBySize.empty())
      +
      9400  {
      +
      9401  return m_FreeSuballocationsBySize.back()->size;
      9402  }
      -
      9403 
      -
      9404  return false;
      -
      9405 }
      -
      9406 
      -
      9407 bool VmaBlockMetadata_Generic::MakeRequestedAllocationsLost(
      -
      9408  uint32_t currentFrameIndex,
      -
      9409  uint32_t frameInUseCount,
      -
      9410  VmaAllocationRequest* pAllocationRequest)
      -
      9411 {
      -
      9412  VMA_ASSERT(pAllocationRequest && pAllocationRequest->type == VmaAllocationRequestType::Normal);
      +
      9403  else
      +
      9404  {
      +
      9405  return 0;
      +
      9406  }
      +
      9407 }
      +
      9408 
      +
      9409 bool VmaBlockMetadata_Generic::IsEmpty() const
      +
      9410 {
      +
      9411  return (m_Suballocations.size() == 1) && (m_FreeCount == 1);
      +
      9412 }
      9413 
      -
      9414  while(pAllocationRequest->itemsToMakeLostCount > 0)
      -
      9415  {
      -
      9416  if(pAllocationRequest->item->type == VMA_SUBALLOCATION_TYPE_FREE)
      -
      9417  {
      -
      9418  ++pAllocationRequest->item;
      -
      9419  }
      -
      9420  VMA_ASSERT(pAllocationRequest->item != m_Suballocations.end());
      -
      9421  VMA_ASSERT(pAllocationRequest->item->hAllocation != VK_NULL_HANDLE);
      -
      9422  VMA_ASSERT(pAllocationRequest->item->hAllocation->CanBecomeLost());
      -
      9423  if(pAllocationRequest->item->hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
      -
      9424  {
      -
      9425  pAllocationRequest->item = FreeSuballocation(pAllocationRequest->item);
      -
      9426  --pAllocationRequest->itemsToMakeLostCount;
      -
      9427  }
      -
      9428  else
      -
      9429  {
      -
      9430  return false;
      -
      9431  }
      -
      9432  }
      -
      9433 
      -
      9434  VMA_HEAVY_ASSERT(Validate());
      -
      9435  VMA_ASSERT(pAllocationRequest->item != m_Suballocations.end());
      -
      9436  VMA_ASSERT(pAllocationRequest->item->type == VMA_SUBALLOCATION_TYPE_FREE);
      -
      9437 
      -
      9438  return true;
      -
      9439 }
      -
      9440 
      -
      9441 uint32_t VmaBlockMetadata_Generic::MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)
      -
      9442 {
      -
      9443  uint32_t lostAllocationCount = 0;
      -
      9444  for(VmaSuballocationList::iterator it = m_Suballocations.begin();
      -
      9445  it != m_Suballocations.end();
      -
      9446  ++it)
      -
      9447  {
      -
      9448  if(it->type != VMA_SUBALLOCATION_TYPE_FREE &&
      -
      9449  it->hAllocation->CanBecomeLost() &&
      -
      9450  it->hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
      -
      9451  {
      -
      9452  it = FreeSuballocation(it);
      -
      9453  ++lostAllocationCount;
      -
      9454  }
      -
      9455  }
      -
      9456  return lostAllocationCount;
      +
      9414 void VmaBlockMetadata_Generic::CalcAllocationStatInfo(VmaStatInfo& outInfo) const
      +
      9415 {
      +
      9416  outInfo.blockCount = 1;
      +
      9417 
      +
      9418  const uint32_t rangeCount = (uint32_t)m_Suballocations.size();
      +
      9419  outInfo.allocationCount = rangeCount - m_FreeCount;
      +
      9420  outInfo.unusedRangeCount = m_FreeCount;
      +
      9421 
      +
      9422  outInfo.unusedBytes = m_SumFreeSize;
      +
      9423  outInfo.usedBytes = GetSize() - outInfo.unusedBytes;
      +
      9424 
      +
      9425  outInfo.allocationSizeMin = UINT64_MAX;
      +
      9426  outInfo.allocationSizeMax = 0;
      +
      9427  outInfo.unusedRangeSizeMin = UINT64_MAX;
      +
      9428  outInfo.unusedRangeSizeMax = 0;
      +
      9429 
      +
      9430  for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin();
      +
      9431  suballocItem != m_Suballocations.cend();
      +
      9432  ++suballocItem)
      +
      9433  {
      +
      9434  const VmaSuballocation& suballoc = *suballocItem;
      +
      9435  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
      +
      9436  {
      +
      9437  outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size);
      +
      9438  outInfo.allocationSizeMax = VMA_MAX(outInfo.allocationSizeMax, suballoc.size);
      +
      9439  }
      +
      9440  else
      +
      9441  {
      +
      9442  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, suballoc.size);
      +
      9443  outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, suballoc.size);
      +
      9444  }
      +
      9445  }
      +
      9446 }
      +
      9447 
      +
      9448 void VmaBlockMetadata_Generic::AddPoolStats(VmaPoolStats& inoutStats) const
      +
      9449 {
      +
      9450  const uint32_t rangeCount = (uint32_t)m_Suballocations.size();
      +
      9451 
      +
      9452  inoutStats.size += GetSize();
      +
      9453  inoutStats.unusedSize += m_SumFreeSize;
      +
      9454  inoutStats.allocationCount += rangeCount - m_FreeCount;
      +
      9455  inoutStats.unusedRangeCount += m_FreeCount;
      +
      9456  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, GetUnusedRangeSizeMax());
      9457 }
      9458 
      -
      9459 VkResult VmaBlockMetadata_Generic::CheckCorruption(const void* pBlockData)
      -
      9460 {
      -
      9461  for(VmaSuballocationList::iterator it = m_Suballocations.begin();
      -
      9462  it != m_Suballocations.end();
      -
      9463  ++it)
      -
      9464  {
      -
      9465  if(it->type != VMA_SUBALLOCATION_TYPE_FREE)
      -
      9466  {
      -
      9467  if(!VmaValidateMagicValue(pBlockData, it->offset - VMA_DEBUG_MARGIN))
      -
      9468  {
      -
      9469  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED BEFORE VALIDATED ALLOCATION!");
      -
      9470  return VK_ERROR_VALIDATION_FAILED_EXT;
      -
      9471  }
      -
      9472  if(!VmaValidateMagicValue(pBlockData, it->offset + it->size))
      -
      9473  {
      -
      9474  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!");
      -
      9475  return VK_ERROR_VALIDATION_FAILED_EXT;
      -
      9476  }
      -
      9477  }
      -
      9478  }
      -
      9479 
      -
      9480  return VK_SUCCESS;
      -
      9481 }
      +
      9459 #if VMA_STATS_STRING_ENABLED
      +
      9460 
      +
      9461 void VmaBlockMetadata_Generic::PrintDetailedMap(class VmaJsonWriter& json) const
      +
      9462 {
      +
      9463  PrintDetailedMap_Begin(json,
      +
      9464  m_SumFreeSize, // unusedBytes
      +
      9465  m_Suballocations.size() - (size_t)m_FreeCount, // allocationCount
      +
      9466  m_FreeCount); // unusedRangeCount
      +
      9467 
      +
      9468  size_t i = 0;
      +
      9469  for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin();
      +
      9470  suballocItem != m_Suballocations.cend();
      +
      9471  ++suballocItem, ++i)
      +
      9472  {
      +
      9473  if(suballocItem->type == VMA_SUBALLOCATION_TYPE_FREE)
      +
      9474  {
      +
      9475  PrintDetailedMap_UnusedRange(json, suballocItem->offset, suballocItem->size);
      +
      9476  }
      +
      9477  else
      +
      9478  {
      +
      9479  PrintDetailedMap_Allocation(json, suballocItem->offset, suballocItem->hAllocation);
      +
      9480  }
      +
      9481  }
      9482 
      -
      9483 void VmaBlockMetadata_Generic::Alloc(
      -
      9484  const VmaAllocationRequest& request,
      -
      9485  VmaSuballocationType type,
      -
      9486  VkDeviceSize allocSize,
      -
      9487  VmaAllocation hAllocation)
      -
      9488 {
      -
      9489  VMA_ASSERT(request.type == VmaAllocationRequestType::Normal);
      -
      9490  VMA_ASSERT(request.item != m_Suballocations.end());
      -
      9491  VmaSuballocation& suballoc = *request.item;
      -
      9492  // Given suballocation is a free block.
      -
      9493  VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
      -
      9494  // Given offset is inside this suballocation.
      -
      9495  VMA_ASSERT(request.offset >= suballoc.offset);
      -
      9496  const VkDeviceSize paddingBegin = request.offset - suballoc.offset;
      -
      9497  VMA_ASSERT(suballoc.size >= paddingBegin + allocSize);
      -
      9498  const VkDeviceSize paddingEnd = suballoc.size - paddingBegin - allocSize;
      -
      9499 
      -
      9500  // Unregister this free suballocation from m_FreeSuballocationsBySize and update
      -
      9501  // it to become used.
      -
      9502  UnregisterFreeSuballocation(request.item);
      -
      9503 
      -
      9504  suballoc.offset = request.offset;
      -
      9505  suballoc.size = allocSize;
      -
      9506  suballoc.type = type;
      -
      9507  suballoc.hAllocation = hAllocation;
      -
      9508 
      -
      9509  // If there are any free bytes remaining at the end, insert new free suballocation after current one.
      -
      9510  if(paddingEnd)
      +
      9483  PrintDetailedMap_End(json);
      +
      9484 }
      +
      9485 
      +
      9486 #endif // #if VMA_STATS_STRING_ENABLED
      +
      9487 
      +
      9488 bool VmaBlockMetadata_Generic::CreateAllocationRequest(
      +
      9489  uint32_t currentFrameIndex,
      +
      9490  uint32_t frameInUseCount,
      +
      9491  VkDeviceSize bufferImageGranularity,
      +
      9492  VkDeviceSize allocSize,
      +
      9493  VkDeviceSize allocAlignment,
      +
      9494  bool upperAddress,
      +
      9495  VmaSuballocationType allocType,
      +
      9496  bool canMakeOtherLost,
      +
      9497  uint32_t strategy,
      +
      9498  VmaAllocationRequest* pAllocationRequest)
      +
      9499 {
      +
      9500  VMA_ASSERT(allocSize > 0);
      +
      9501  VMA_ASSERT(!upperAddress);
      +
      9502  VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE);
      +
      9503  VMA_ASSERT(pAllocationRequest != VMA_NULL);
      +
      9504  VMA_HEAVY_ASSERT(Validate());
      +
      9505 
      +
      9506  pAllocationRequest->type = VmaAllocationRequestType::Normal;
      +
      9507 
      +
      9508  // There is not enough total free space in this block to fullfill the request: Early return.
      +
      9509  if(canMakeOtherLost == false &&
      +
      9510  m_SumFreeSize < allocSize + 2 * VMA_DEBUG_MARGIN)
      9511  {
      -
      9512  VmaSuballocation paddingSuballoc = {};
      -
      9513  paddingSuballoc.offset = request.offset + allocSize;
      -
      9514  paddingSuballoc.size = paddingEnd;
      -
      9515  paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
      -
      9516  VmaSuballocationList::iterator next = request.item;
      -
      9517  ++next;
      -
      9518  const VmaSuballocationList::iterator paddingEndItem =
      -
      9519  m_Suballocations.insert(next, paddingSuballoc);
      -
      9520  RegisterFreeSuballocation(paddingEndItem);
      -
      9521  }
      -
      9522 
      -
      9523  // If there are any free bytes remaining at the beginning, insert new free suballocation before current one.
      -
      9524  if(paddingBegin)
      -
      9525  {
      -
      9526  VmaSuballocation paddingSuballoc = {};
      -
      9527  paddingSuballoc.offset = request.offset - paddingBegin;
      -
      9528  paddingSuballoc.size = paddingBegin;
      -
      9529  paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
      -
      9530  const VmaSuballocationList::iterator paddingBeginItem =
      -
      9531  m_Suballocations.insert(request.item, paddingSuballoc);
      -
      9532  RegisterFreeSuballocation(paddingBeginItem);
      -
      9533  }
      -
      9534 
      -
      9535  // Update totals.
      -
      9536  m_FreeCount = m_FreeCount - 1;
      -
      9537  if(paddingBegin > 0)
      -
      9538  {
      -
      9539  ++m_FreeCount;
      -
      9540  }
      -
      9541  if(paddingEnd > 0)
      -
      9542  {
      -
      9543  ++m_FreeCount;
      -
      9544  }
      -
      9545  m_SumFreeSize -= allocSize;
      -
      9546 }
      -
      9547 
      -
      9548 void VmaBlockMetadata_Generic::Free(const VmaAllocation allocation)
      -
      9549 {
      -
      9550  for(VmaSuballocationList::iterator suballocItem = m_Suballocations.begin();
      -
      9551  suballocItem != m_Suballocations.end();
      -
      9552  ++suballocItem)
      -
      9553  {
      -
      9554  VmaSuballocation& suballoc = *suballocItem;
      -
      9555  if(suballoc.hAllocation == allocation)
      -
      9556  {
      -
      9557  FreeSuballocation(suballocItem);
      -
      9558  VMA_HEAVY_ASSERT(Validate());
      -
      9559  return;
      -
      9560  }
      -
      9561  }
      -
      9562  VMA_ASSERT(0 && "Not found!");
      -
      9563 }
      -
      9564 
      -
      9565 void VmaBlockMetadata_Generic::FreeAtOffset(VkDeviceSize offset)
      -
      9566 {
      -
      9567  for(VmaSuballocationList::iterator suballocItem = m_Suballocations.begin();
      -
      9568  suballocItem != m_Suballocations.end();
      -
      9569  ++suballocItem)
      -
      9570  {
      -
      9571  VmaSuballocation& suballoc = *suballocItem;
      -
      9572  if(suballoc.offset == offset)
      -
      9573  {
      -
      9574  FreeSuballocation(suballocItem);
      -
      9575  return;
      -
      9576  }
      -
      9577  }
      -
      9578  VMA_ASSERT(0 && "Not found!");
      -
      9579 }
      -
      9580 
      -
      9581 bool VmaBlockMetadata_Generic::ValidateFreeSuballocationList() const
      -
      9582 {
      -
      9583  VkDeviceSize lastSize = 0;
      -
      9584  for(size_t i = 0, count = m_FreeSuballocationsBySize.size(); i < count; ++i)
      -
      9585  {
      -
      9586  const VmaSuballocationList::iterator it = m_FreeSuballocationsBySize[i];
      -
      9587 
      -
      9588  VMA_VALIDATE(it->type == VMA_SUBALLOCATION_TYPE_FREE);
      -
      9589  VMA_VALIDATE(it->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER);
      -
      9590  VMA_VALIDATE(it->size >= lastSize);
      -
      9591  lastSize = it->size;
      -
      9592  }
      -
      9593  return true;
      -
      9594 }
      -
      9595 
      -
      9596 bool VmaBlockMetadata_Generic::CheckAllocation(
      -
      9597  uint32_t currentFrameIndex,
      -
      9598  uint32_t frameInUseCount,
      -
      9599  VkDeviceSize bufferImageGranularity,
      -
      9600  VkDeviceSize allocSize,
      -
      9601  VkDeviceSize allocAlignment,
      -
      9602  VmaSuballocationType allocType,
      -
      9603  VmaSuballocationList::const_iterator suballocItem,
      -
      9604  bool canMakeOtherLost,
      -
      9605  VkDeviceSize* pOffset,
      -
      9606  size_t* itemsToMakeLostCount,
      -
      9607  VkDeviceSize* pSumFreeSize,
      -
      9608  VkDeviceSize* pSumItemSize) const
      -
      9609 {
      -
      9610  VMA_ASSERT(allocSize > 0);
      -
      9611  VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE);
      -
      9612  VMA_ASSERT(suballocItem != m_Suballocations.cend());
      -
      9613  VMA_ASSERT(pOffset != VMA_NULL);
      -
      9614 
      -
      9615  *itemsToMakeLostCount = 0;
      -
      9616  *pSumFreeSize = 0;
      -
      9617  *pSumItemSize = 0;
      -
      9618 
      -
      9619  if(canMakeOtherLost)
      -
      9620  {
      -
      9621  if(suballocItem->type == VMA_SUBALLOCATION_TYPE_FREE)
      -
      9622  {
      -
      9623  *pSumFreeSize = suballocItem->size;
      -
      9624  }
      -
      9625  else
      -
      9626  {
      -
      9627  if(suballocItem->hAllocation->CanBecomeLost() &&
      -
      9628  suballocItem->hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
      -
      9629  {
      -
      9630  ++*itemsToMakeLostCount;
      -
      9631  *pSumItemSize = suballocItem->size;
      -
      9632  }
      -
      9633  else
      -
      9634  {
      -
      9635  return false;
      -
      9636  }
      -
      9637  }
      -
      9638 
      -
      9639  // Remaining size is too small for this request: Early return.
      -
      9640  if(GetSize() - suballocItem->offset < allocSize)
      -
      9641  {
      -
      9642  return false;
      -
      9643  }
      -
      9644 
      -
      9645  // Start from offset equal to beginning of this suballocation.
      -
      9646  *pOffset = suballocItem->offset;
      -
      9647 
      -
      9648  // Apply VMA_DEBUG_MARGIN at the beginning.
      -
      9649  if(VMA_DEBUG_MARGIN > 0)
      -
      9650  {
      -
      9651  *pOffset += VMA_DEBUG_MARGIN;
      -
      9652  }
      -
      9653 
      -
      9654  // Apply alignment.
      -
      9655  *pOffset = VmaAlignUp(*pOffset, allocAlignment);
      +
      9512  return false;
      +
      9513  }
      +
      9514 
      +
      9515  // New algorithm, efficiently searching freeSuballocationsBySize.
      +
      9516  const size_t freeSuballocCount = m_FreeSuballocationsBySize.size();
      +
      9517  if(freeSuballocCount > 0)
      +
      9518  {
      + +
      9520  {
      +
      9521  // Find first free suballocation with size not less than allocSize + 2 * VMA_DEBUG_MARGIN.
      +
      9522  VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess(
      +
      9523  m_FreeSuballocationsBySize.data(),
      +
      9524  m_FreeSuballocationsBySize.data() + freeSuballocCount,
      +
      9525  allocSize + 2 * VMA_DEBUG_MARGIN,
      +
      9526  VmaSuballocationItemSizeLess());
      +
      9527  size_t index = it - m_FreeSuballocationsBySize.data();
      +
      9528  for(; index < freeSuballocCount; ++index)
      +
      9529  {
      +
      9530  if(CheckAllocation(
      +
      9531  currentFrameIndex,
      +
      9532  frameInUseCount,
      +
      9533  bufferImageGranularity,
      +
      9534  allocSize,
      +
      9535  allocAlignment,
      +
      9536  allocType,
      +
      9537  m_FreeSuballocationsBySize[index],
      +
      9538  false, // canMakeOtherLost
      +
      9539  &pAllocationRequest->offset,
      +
      9540  &pAllocationRequest->itemsToMakeLostCount,
      +
      9541  &pAllocationRequest->sumFreeSize,
      +
      9542  &pAllocationRequest->sumItemSize))
      +
      9543  {
      +
      9544  pAllocationRequest->item = m_FreeSuballocationsBySize[index];
      +
      9545  return true;
      +
      9546  }
      +
      9547  }
      +
      9548  }
      +
      9549  else if(strategy == VMA_ALLOCATION_INTERNAL_STRATEGY_MIN_OFFSET)
      +
      9550  {
      +
      9551  for(VmaSuballocationList::iterator it = m_Suballocations.begin();
      +
      9552  it != m_Suballocations.end();
      +
      9553  ++it)
      +
      9554  {
      +
      9555  if(it->type == VMA_SUBALLOCATION_TYPE_FREE && CheckAllocation(
      +
      9556  currentFrameIndex,
      +
      9557  frameInUseCount,
      +
      9558  bufferImageGranularity,
      +
      9559  allocSize,
      +
      9560  allocAlignment,
      +
      9561  allocType,
      +
      9562  it,
      +
      9563  false, // canMakeOtherLost
      +
      9564  &pAllocationRequest->offset,
      +
      9565  &pAllocationRequest->itemsToMakeLostCount,
      +
      9566  &pAllocationRequest->sumFreeSize,
      +
      9567  &pAllocationRequest->sumItemSize))
      +
      9568  {
      +
      9569  pAllocationRequest->item = it;
      +
      9570  return true;
      +
      9571  }
      +
      9572  }
      +
      9573  }
      +
      9574  else // WORST_FIT, FIRST_FIT
      +
      9575  {
      +
      9576  // Search staring from biggest suballocations.
      +
      9577  for(size_t index = freeSuballocCount; index--; )
      +
      9578  {
      +
      9579  if(CheckAllocation(
      +
      9580  currentFrameIndex,
      +
      9581  frameInUseCount,
      +
      9582  bufferImageGranularity,
      +
      9583  allocSize,
      +
      9584  allocAlignment,
      +
      9585  allocType,
      +
      9586  m_FreeSuballocationsBySize[index],
      +
      9587  false, // canMakeOtherLost
      +
      9588  &pAllocationRequest->offset,
      +
      9589  &pAllocationRequest->itemsToMakeLostCount,
      +
      9590  &pAllocationRequest->sumFreeSize,
      +
      9591  &pAllocationRequest->sumItemSize))
      +
      9592  {
      +
      9593  pAllocationRequest->item = m_FreeSuballocationsBySize[index];
      +
      9594  return true;
      +
      9595  }
      +
      9596  }
      +
      9597  }
      +
      9598  }
      +
      9599 
      +
      9600  if(canMakeOtherLost)
      +
      9601  {
      +
      9602  // Brute-force algorithm. TODO: Come up with something better.
      +
      9603 
      +
      9604  bool found = false;
      +
      9605  VmaAllocationRequest tmpAllocRequest = {};
      +
      9606  tmpAllocRequest.type = VmaAllocationRequestType::Normal;
      +
      9607  for(VmaSuballocationList::iterator suballocIt = m_Suballocations.begin();
      +
      9608  suballocIt != m_Suballocations.end();
      +
      9609  ++suballocIt)
      +
      9610  {
      +
      9611  if(suballocIt->type == VMA_SUBALLOCATION_TYPE_FREE ||
      +
      9612  suballocIt->hAllocation->CanBecomeLost())
      +
      9613  {
      +
      9614  if(CheckAllocation(
      +
      9615  currentFrameIndex,
      +
      9616  frameInUseCount,
      +
      9617  bufferImageGranularity,
      +
      9618  allocSize,
      +
      9619  allocAlignment,
      +
      9620  allocType,
      +
      9621  suballocIt,
      +
      9622  canMakeOtherLost,
      +
      9623  &tmpAllocRequest.offset,
      +
      9624  &tmpAllocRequest.itemsToMakeLostCount,
      +
      9625  &tmpAllocRequest.sumFreeSize,
      +
      9626  &tmpAllocRequest.sumItemSize))
      +
      9627  {
      + +
      9629  {
      +
      9630  *pAllocationRequest = tmpAllocRequest;
      +
      9631  pAllocationRequest->item = suballocIt;
      +
      9632  break;
      +
      9633  }
      +
      9634  if(!found || tmpAllocRequest.CalcCost() < pAllocationRequest->CalcCost())
      +
      9635  {
      +
      9636  *pAllocationRequest = tmpAllocRequest;
      +
      9637  pAllocationRequest->item = suballocIt;
      +
      9638  found = true;
      +
      9639  }
      +
      9640  }
      +
      9641  }
      +
      9642  }
      +
      9643 
      +
      9644  return found;
      +
      9645  }
      +
      9646 
      +
      9647  return false;
      +
      9648 }
      +
      9649 
      +
      9650 bool VmaBlockMetadata_Generic::MakeRequestedAllocationsLost(
      +
      9651  uint32_t currentFrameIndex,
      +
      9652  uint32_t frameInUseCount,
      +
      9653  VmaAllocationRequest* pAllocationRequest)
      +
      9654 {
      +
      9655  VMA_ASSERT(pAllocationRequest && pAllocationRequest->type == VmaAllocationRequestType::Normal);
      9656 
      -
      9657  // Check previous suballocations for BufferImageGranularity conflicts.
      -
      9658  // Make bigger alignment if necessary.
      -
      9659  if(bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment)
      +
      9657  while(pAllocationRequest->itemsToMakeLostCount > 0)
      +
      9658  {
      +
      9659  if(pAllocationRequest->item->type == VMA_SUBALLOCATION_TYPE_FREE)
      9660  {
      -
      9661  bool bufferImageGranularityConflict = false;
      -
      9662  VmaSuballocationList::const_iterator prevSuballocItem = suballocItem;
      -
      9663  while(prevSuballocItem != m_Suballocations.cbegin())
      -
      9664  {
      -
      9665  --prevSuballocItem;
      -
      9666  const VmaSuballocation& prevSuballoc = *prevSuballocItem;
      -
      9667  if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, *pOffset, bufferImageGranularity))
      -
      9668  {
      -
      9669  if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType))
      -
      9670  {
      -
      9671  bufferImageGranularityConflict = true;
      -
      9672  break;
      -
      9673  }
      -
      9674  }
      -
      9675  else
      -
      9676  // Already on previous page.
      -
      9677  break;
      -
      9678  }
      -
      9679  if(bufferImageGranularityConflict)
      -
      9680  {
      -
      9681  *pOffset = VmaAlignUp(*pOffset, bufferImageGranularity);
      -
      9682  }
      -
      9683  }
      -
      9684 
      -
      9685  // Now that we have final *pOffset, check if we are past suballocItem.
      -
      9686  // If yes, return false - this function should be called for another suballocItem as starting point.
      -
      9687  if(*pOffset >= suballocItem->offset + suballocItem->size)
      -
      9688  {
      -
      9689  return false;
      -
      9690  }
      -
      9691 
      -
      9692  // Calculate padding at the beginning based on current offset.
      -
      9693  const VkDeviceSize paddingBegin = *pOffset - suballocItem->offset;
      -
      9694 
      -
      9695  // Calculate required margin at the end.
      -
      9696  const VkDeviceSize requiredEndMargin = VMA_DEBUG_MARGIN;
      -
      9697 
      -
      9698  const VkDeviceSize totalSize = paddingBegin + allocSize + requiredEndMargin;
      -
      9699  // Another early return check.
      -
      9700  if(suballocItem->offset + totalSize > GetSize())
      -
      9701  {
      -
      9702  return false;
      -
      9703  }
      -
      9704 
      -
      9705  // Advance lastSuballocItem until desired size is reached.
      -
      9706  // Update itemsToMakeLostCount.
      -
      9707  VmaSuballocationList::const_iterator lastSuballocItem = suballocItem;
      -
      9708  if(totalSize > suballocItem->size)
      +
      9661  ++pAllocationRequest->item;
      +
      9662  }
      +
      9663  VMA_ASSERT(pAllocationRequest->item != m_Suballocations.end());
      +
      9664  VMA_ASSERT(pAllocationRequest->item->hAllocation != VK_NULL_HANDLE);
      +
      9665  VMA_ASSERT(pAllocationRequest->item->hAllocation->CanBecomeLost());
      +
      9666  if(pAllocationRequest->item->hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
      +
      9667  {
      +
      9668  pAllocationRequest->item = FreeSuballocation(pAllocationRequest->item);
      +
      9669  --pAllocationRequest->itemsToMakeLostCount;
      +
      9670  }
      +
      9671  else
      +
      9672  {
      +
      9673  return false;
      +
      9674  }
      +
      9675  }
      +
      9676 
      +
      9677  VMA_HEAVY_ASSERT(Validate());
      +
      9678  VMA_ASSERT(pAllocationRequest->item != m_Suballocations.end());
      +
      9679  VMA_ASSERT(pAllocationRequest->item->type == VMA_SUBALLOCATION_TYPE_FREE);
      +
      9680 
      +
      9681  return true;
      +
      9682 }
      +
      9683 
      +
      9684 uint32_t VmaBlockMetadata_Generic::MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)
      +
      9685 {
      +
      9686  uint32_t lostAllocationCount = 0;
      +
      9687  for(VmaSuballocationList::iterator it = m_Suballocations.begin();
      +
      9688  it != m_Suballocations.end();
      +
      9689  ++it)
      +
      9690  {
      +
      9691  if(it->type != VMA_SUBALLOCATION_TYPE_FREE &&
      +
      9692  it->hAllocation->CanBecomeLost() &&
      +
      9693  it->hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
      +
      9694  {
      +
      9695  it = FreeSuballocation(it);
      +
      9696  ++lostAllocationCount;
      +
      9697  }
      +
      9698  }
      +
      9699  return lostAllocationCount;
      +
      9700 }
      +
      9701 
      +
      9702 VkResult VmaBlockMetadata_Generic::CheckCorruption(const void* pBlockData)
      +
      9703 {
      +
      9704  for(VmaSuballocationList::iterator it = m_Suballocations.begin();
      +
      9705  it != m_Suballocations.end();
      +
      9706  ++it)
      +
      9707  {
      +
      9708  if(it->type != VMA_SUBALLOCATION_TYPE_FREE)
      9709  {
      -
      9710  VkDeviceSize remainingSize = totalSize - suballocItem->size;
      -
      9711  while(remainingSize > 0)
      -
      9712  {
      -
      9713  ++lastSuballocItem;
      -
      9714  if(lastSuballocItem == m_Suballocations.cend())
      -
      9715  {
      -
      9716  return false;
      -
      9717  }
      -
      9718  if(lastSuballocItem->type == VMA_SUBALLOCATION_TYPE_FREE)
      -
      9719  {
      -
      9720  *pSumFreeSize += lastSuballocItem->size;
      -
      9721  }
      -
      9722  else
      -
      9723  {
      -
      9724  VMA_ASSERT(lastSuballocItem->hAllocation != VK_NULL_HANDLE);
      -
      9725  if(lastSuballocItem->hAllocation->CanBecomeLost() &&
      -
      9726  lastSuballocItem->hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
      -
      9727  {
      -
      9728  ++*itemsToMakeLostCount;
      -
      9729  *pSumItemSize += lastSuballocItem->size;
      -
      9730  }
      -
      9731  else
      -
      9732  {
      -
      9733  return false;
      -
      9734  }
      -
      9735  }
      -
      9736  remainingSize = (lastSuballocItem->size < remainingSize) ?
      -
      9737  remainingSize - lastSuballocItem->size : 0;
      -
      9738  }
      -
      9739  }
      -
      9740 
      -
      9741  // Check next suballocations for BufferImageGranularity conflicts.
      -
      9742  // If conflict exists, we must mark more allocations lost or fail.
      -
      9743  if(allocSize % bufferImageGranularity || *pOffset % bufferImageGranularity)
      -
      9744  {
      -
      9745  VmaSuballocationList::const_iterator nextSuballocItem = lastSuballocItem;
      -
      9746  ++nextSuballocItem;
      -
      9747  while(nextSuballocItem != m_Suballocations.cend())
      -
      9748  {
      -
      9749  const VmaSuballocation& nextSuballoc = *nextSuballocItem;
      -
      9750  if(VmaBlocksOnSamePage(*pOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
      -
      9751  {
      -
      9752  if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type))
      -
      9753  {
      -
      9754  VMA_ASSERT(nextSuballoc.hAllocation != VK_NULL_HANDLE);
      -
      9755  if(nextSuballoc.hAllocation->CanBecomeLost() &&
      -
      9756  nextSuballoc.hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
      -
      9757  {
      -
      9758  ++*itemsToMakeLostCount;
      -
      9759  }
      -
      9760  else
      -
      9761  {
      -
      9762  return false;
      -
      9763  }
      -
      9764  }
      -
      9765  }
      -
      9766  else
      -
      9767  {
      -
      9768  // Already on next page.
      -
      9769  break;
      -
      9770  }
      -
      9771  ++nextSuballocItem;
      -
      9772  }
      -
      9773  }
      -
      9774  }
      -
      9775  else
      -
      9776  {
      -
      9777  const VmaSuballocation& suballoc = *suballocItem;
      -
      9778  VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
      -
      9779 
      -
      9780  *pSumFreeSize = suballoc.size;
      -
      9781 
      -
      9782  // Size of this suballocation is too small for this request: Early return.
      -
      9783  if(suballoc.size < allocSize)
      -
      9784  {
      -
      9785  return false;
      -
      9786  }
      -
      9787 
      -
      9788  // Start from offset equal to beginning of this suballocation.
      -
      9789  *pOffset = suballoc.offset;
      +
      9710  if(!VmaValidateMagicValue(pBlockData, it->offset - VMA_DEBUG_MARGIN))
      +
      9711  {
      +
      9712  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED BEFORE VALIDATED ALLOCATION!");
      +
      9713  return VK_ERROR_VALIDATION_FAILED_EXT;
      +
      9714  }
      +
      9715  if(!VmaValidateMagicValue(pBlockData, it->offset + it->size))
      +
      9716  {
      +
      9717  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!");
      +
      9718  return VK_ERROR_VALIDATION_FAILED_EXT;
      +
      9719  }
      +
      9720  }
      +
      9721  }
      +
      9722 
      +
      9723  return VK_SUCCESS;
      +
      9724 }
      +
      9725 
      +
      9726 void VmaBlockMetadata_Generic::Alloc(
      +
      9727  const VmaAllocationRequest& request,
      +
      9728  VmaSuballocationType type,
      +
      9729  VkDeviceSize allocSize,
      +
      9730  VmaAllocation hAllocation)
      +
      9731 {
      +
      9732  VMA_ASSERT(request.type == VmaAllocationRequestType::Normal);
      +
      9733  VMA_ASSERT(request.item != m_Suballocations.end());
      +
      9734  VmaSuballocation& suballoc = *request.item;
      +
      9735  // Given suballocation is a free block.
      +
      9736  VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
      +
      9737  // Given offset is inside this suballocation.
      +
      9738  VMA_ASSERT(request.offset >= suballoc.offset);
      +
      9739  const VkDeviceSize paddingBegin = request.offset - suballoc.offset;
      +
      9740  VMA_ASSERT(suballoc.size >= paddingBegin + allocSize);
      +
      9741  const VkDeviceSize paddingEnd = suballoc.size - paddingBegin - allocSize;
      +
      9742 
      +
      9743  // Unregister this free suballocation from m_FreeSuballocationsBySize and update
      +
      9744  // it to become used.
      +
      9745  UnregisterFreeSuballocation(request.item);
      +
      9746 
      +
      9747  suballoc.offset = request.offset;
      +
      9748  suballoc.size = allocSize;
      +
      9749  suballoc.type = type;
      +
      9750  suballoc.hAllocation = hAllocation;
      +
      9751 
      +
      9752  // If there are any free bytes remaining at the end, insert new free suballocation after current one.
      +
      9753  if(paddingEnd)
      +
      9754  {
      +
      9755  VmaSuballocation paddingSuballoc = {};
      +
      9756  paddingSuballoc.offset = request.offset + allocSize;
      +
      9757  paddingSuballoc.size = paddingEnd;
      +
      9758  paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
      +
      9759  VmaSuballocationList::iterator next = request.item;
      +
      9760  ++next;
      +
      9761  const VmaSuballocationList::iterator paddingEndItem =
      +
      9762  m_Suballocations.insert(next, paddingSuballoc);
      +
      9763  RegisterFreeSuballocation(paddingEndItem);
      +
      9764  }
      +
      9765 
      +
      9766  // If there are any free bytes remaining at the beginning, insert new free suballocation before current one.
      +
      9767  if(paddingBegin)
      +
      9768  {
      +
      9769  VmaSuballocation paddingSuballoc = {};
      +
      9770  paddingSuballoc.offset = request.offset - paddingBegin;
      +
      9771  paddingSuballoc.size = paddingBegin;
      +
      9772  paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
      +
      9773  const VmaSuballocationList::iterator paddingBeginItem =
      +
      9774  m_Suballocations.insert(request.item, paddingSuballoc);
      +
      9775  RegisterFreeSuballocation(paddingBeginItem);
      +
      9776  }
      +
      9777 
      +
      9778  // Update totals.
      +
      9779  m_FreeCount = m_FreeCount - 1;
      +
      9780  if(paddingBegin > 0)
      +
      9781  {
      +
      9782  ++m_FreeCount;
      +
      9783  }
      +
      9784  if(paddingEnd > 0)
      +
      9785  {
      +
      9786  ++m_FreeCount;
      +
      9787  }
      +
      9788  m_SumFreeSize -= allocSize;
      +
      9789 }
      9790 
      -
      9791  // Apply VMA_DEBUG_MARGIN at the beginning.
      -
      9792  if(VMA_DEBUG_MARGIN > 0)
      -
      9793  {
      -
      9794  *pOffset += VMA_DEBUG_MARGIN;
      -
      9795  }
      -
      9796 
      -
      9797  // Apply alignment.
      -
      9798  *pOffset = VmaAlignUp(*pOffset, allocAlignment);
      -
      9799 
      -
      9800  // Check previous suballocations for BufferImageGranularity conflicts.
      -
      9801  // Make bigger alignment if necessary.
      -
      9802  if(bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment)
      -
      9803  {
      -
      9804  bool bufferImageGranularityConflict = false;
      -
      9805  VmaSuballocationList::const_iterator prevSuballocItem = suballocItem;
      -
      9806  while(prevSuballocItem != m_Suballocations.cbegin())
      -
      9807  {
      -
      9808  --prevSuballocItem;
      -
      9809  const VmaSuballocation& prevSuballoc = *prevSuballocItem;
      -
      9810  if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, *pOffset, bufferImageGranularity))
      -
      9811  {
      -
      9812  if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType))
      -
      9813  {
      -
      9814  bufferImageGranularityConflict = true;
      -
      9815  break;
      -
      9816  }
      -
      9817  }
      -
      9818  else
      -
      9819  // Already on previous page.
      -
      9820  break;
      -
      9821  }
      -
      9822  if(bufferImageGranularityConflict)
      -
      9823  {
      -
      9824  *pOffset = VmaAlignUp(*pOffset, bufferImageGranularity);
      -
      9825  }
      -
      9826  }
      -
      9827 
      -
      9828  // Calculate padding at the beginning based on current offset.
      -
      9829  const VkDeviceSize paddingBegin = *pOffset - suballoc.offset;
      +
      9791 void VmaBlockMetadata_Generic::Free(const VmaAllocation allocation)
      +
      9792 {
      +
      9793  for(VmaSuballocationList::iterator suballocItem = m_Suballocations.begin();
      +
      9794  suballocItem != m_Suballocations.end();
      +
      9795  ++suballocItem)
      +
      9796  {
      +
      9797  VmaSuballocation& suballoc = *suballocItem;
      +
      9798  if(suballoc.hAllocation == allocation)
      +
      9799  {
      +
      9800  FreeSuballocation(suballocItem);
      +
      9801  VMA_HEAVY_ASSERT(Validate());
      +
      9802  return;
      +
      9803  }
      +
      9804  }
      +
      9805  VMA_ASSERT(0 && "Not found!");
      +
      9806 }
      +
      9807 
      +
      9808 void VmaBlockMetadata_Generic::FreeAtOffset(VkDeviceSize offset)
      +
      9809 {
      +
      9810  for(VmaSuballocationList::iterator suballocItem = m_Suballocations.begin();
      +
      9811  suballocItem != m_Suballocations.end();
      +
      9812  ++suballocItem)
      +
      9813  {
      +
      9814  VmaSuballocation& suballoc = *suballocItem;
      +
      9815  if(suballoc.offset == offset)
      +
      9816  {
      +
      9817  FreeSuballocation(suballocItem);
      +
      9818  return;
      +
      9819  }
      +
      9820  }
      +
      9821  VMA_ASSERT(0 && "Not found!");
      +
      9822 }
      +
      9823 
      +
      9824 bool VmaBlockMetadata_Generic::ValidateFreeSuballocationList() const
      +
      9825 {
      +
      9826  VkDeviceSize lastSize = 0;
      +
      9827  for(size_t i = 0, count = m_FreeSuballocationsBySize.size(); i < count; ++i)
      +
      9828  {
      +
      9829  const VmaSuballocationList::iterator it = m_FreeSuballocationsBySize[i];
      9830 
      -
      9831  // Calculate required margin at the end.
      -
      9832  const VkDeviceSize requiredEndMargin = VMA_DEBUG_MARGIN;
      -
      9833 
      -
      9834  // Fail if requested size plus margin before and after is bigger than size of this suballocation.
      -
      9835  if(paddingBegin + allocSize + requiredEndMargin > suballoc.size)
      -
      9836  {
      -
      9837  return false;
      -
      9838  }
      -
      9839 
      -
      9840  // Check next suballocations for BufferImageGranularity conflicts.
      -
      9841  // If conflict exists, allocation cannot be made here.
      -
      9842  if(allocSize % bufferImageGranularity || *pOffset % bufferImageGranularity)
      -
      9843  {
      -
      9844  VmaSuballocationList::const_iterator nextSuballocItem = suballocItem;
      -
      9845  ++nextSuballocItem;
      -
      9846  while(nextSuballocItem != m_Suballocations.cend())
      -
      9847  {
      -
      9848  const VmaSuballocation& nextSuballoc = *nextSuballocItem;
      -
      9849  if(VmaBlocksOnSamePage(*pOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
      -
      9850  {
      -
      9851  if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type))
      -
      9852  {
      -
      9853  return false;
      -
      9854  }
      -
      9855  }
      -
      9856  else
      -
      9857  {
      -
      9858  // Already on next page.
      -
      9859  break;
      -
      9860  }
      -
      9861  ++nextSuballocItem;
      -
      9862  }
      -
      9863  }
      -
      9864  }
      -
      9865 
      -
      9866  // All tests passed: Success. pOffset is already filled.
      -
      9867  return true;
      -
      9868 }
      -
      9869 
      -
      9870 void VmaBlockMetadata_Generic::MergeFreeWithNext(VmaSuballocationList::iterator item)
      -
      9871 {
      -
      9872  VMA_ASSERT(item != m_Suballocations.end());
      -
      9873  VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
      -
      9874 
      -
      9875  VmaSuballocationList::iterator nextItem = item;
      -
      9876  ++nextItem;
      -
      9877  VMA_ASSERT(nextItem != m_Suballocations.end());
      -
      9878  VMA_ASSERT(nextItem->type == VMA_SUBALLOCATION_TYPE_FREE);
      -
      9879 
      -
      9880  item->size += nextItem->size;
      -
      9881  --m_FreeCount;
      -
      9882  m_Suballocations.erase(nextItem);
      -
      9883 }
      -
      9884 
      -
      9885 VmaSuballocationList::iterator VmaBlockMetadata_Generic::FreeSuballocation(VmaSuballocationList::iterator suballocItem)
      -
      9886 {
      -
      9887  // Change this suballocation to be marked as free.
      -
      9888  VmaSuballocation& suballoc = *suballocItem;
      -
      9889  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
      -
      9890  suballoc.hAllocation = VK_NULL_HANDLE;
      -
      9891 
      -
      9892  // Update totals.
      -
      9893  ++m_FreeCount;
      -
      9894  m_SumFreeSize += suballoc.size;
      -
      9895 
      -
      9896  // Merge with previous and/or next suballocation if it's also free.
      -
      9897  bool mergeWithNext = false;
      -
      9898  bool mergeWithPrev = false;
      +
      9831  VMA_VALIDATE(it->type == VMA_SUBALLOCATION_TYPE_FREE);
      +
      9832  VMA_VALIDATE(it->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER);
      +
      9833  VMA_VALIDATE(it->size >= lastSize);
      +
      9834  lastSize = it->size;
      +
      9835  }
      +
      9836  return true;
      +
      9837 }
      +
      9838 
      +
      9839 bool VmaBlockMetadata_Generic::CheckAllocation(
      +
      9840  uint32_t currentFrameIndex,
      +
      9841  uint32_t frameInUseCount,
      +
      9842  VkDeviceSize bufferImageGranularity,
      +
      9843  VkDeviceSize allocSize,
      +
      9844  VkDeviceSize allocAlignment,
      +
      9845  VmaSuballocationType allocType,
      +
      9846  VmaSuballocationList::const_iterator suballocItem,
      +
      9847  bool canMakeOtherLost,
      +
      9848  VkDeviceSize* pOffset,
      +
      9849  size_t* itemsToMakeLostCount,
      +
      9850  VkDeviceSize* pSumFreeSize,
      +
      9851  VkDeviceSize* pSumItemSize) const
      +
      9852 {
      +
      9853  VMA_ASSERT(allocSize > 0);
      +
      9854  VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE);
      +
      9855  VMA_ASSERT(suballocItem != m_Suballocations.cend());
      +
      9856  VMA_ASSERT(pOffset != VMA_NULL);
      +
      9857 
      +
      9858  *itemsToMakeLostCount = 0;
      +
      9859  *pSumFreeSize = 0;
      +
      9860  *pSumItemSize = 0;
      +
      9861 
      +
      9862  if(canMakeOtherLost)
      +
      9863  {
      +
      9864  if(suballocItem->type == VMA_SUBALLOCATION_TYPE_FREE)
      +
      9865  {
      +
      9866  *pSumFreeSize = suballocItem->size;
      +
      9867  }
      +
      9868  else
      +
      9869  {
      +
      9870  if(suballocItem->hAllocation->CanBecomeLost() &&
      +
      9871  suballocItem->hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
      +
      9872  {
      +
      9873  ++*itemsToMakeLostCount;
      +
      9874  *pSumItemSize = suballocItem->size;
      +
      9875  }
      +
      9876  else
      +
      9877  {
      +
      9878  return false;
      +
      9879  }
      +
      9880  }
      +
      9881 
      +
      9882  // Remaining size is too small for this request: Early return.
      +
      9883  if(GetSize() - suballocItem->offset < allocSize)
      +
      9884  {
      +
      9885  return false;
      +
      9886  }
      +
      9887 
      +
      9888  // Start from offset equal to beginning of this suballocation.
      +
      9889  *pOffset = suballocItem->offset;
      +
      9890 
      +
      9891  // Apply VMA_DEBUG_MARGIN at the beginning.
      +
      9892  if(VMA_DEBUG_MARGIN > 0)
      +
      9893  {
      +
      9894  *pOffset += VMA_DEBUG_MARGIN;
      +
      9895  }
      +
      9896 
      +
      9897  // Apply alignment.
      +
      9898  *pOffset = VmaAlignUp(*pOffset, allocAlignment);
      9899 
      -
      9900  VmaSuballocationList::iterator nextItem = suballocItem;
      -
      9901  ++nextItem;
      -
      9902  if((nextItem != m_Suballocations.end()) && (nextItem->type == VMA_SUBALLOCATION_TYPE_FREE))
      -
      9903  {
      -
      9904  mergeWithNext = true;
      -
      9905  }
      -
      9906 
      -
      9907  VmaSuballocationList::iterator prevItem = suballocItem;
      -
      9908  if(suballocItem != m_Suballocations.begin())
      -
      9909  {
      -
      9910  --prevItem;
      -
      9911  if(prevItem->type == VMA_SUBALLOCATION_TYPE_FREE)
      -
      9912  {
      -
      9913  mergeWithPrev = true;
      -
      9914  }
      -
      9915  }
      -
      9916 
      -
      9917  if(mergeWithNext)
      -
      9918  {
      -
      9919  UnregisterFreeSuballocation(nextItem);
      -
      9920  MergeFreeWithNext(suballocItem);
      -
      9921  }
      -
      9922 
      -
      9923  if(mergeWithPrev)
      -
      9924  {
      -
      9925  UnregisterFreeSuballocation(prevItem);
      -
      9926  MergeFreeWithNext(prevItem);
      -
      9927  RegisterFreeSuballocation(prevItem);
      -
      9928  return prevItem;
      -
      9929  }
      -
      9930  else
      -
      9931  {
      -
      9932  RegisterFreeSuballocation(suballocItem);
      -
      9933  return suballocItem;
      -
      9934  }
      -
      9935 }
      -
      9936 
      -
      9937 void VmaBlockMetadata_Generic::RegisterFreeSuballocation(VmaSuballocationList::iterator item)
      -
      9938 {
      -
      9939  VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
      -
      9940  VMA_ASSERT(item->size > 0);
      -
      9941 
      -
      9942  // You may want to enable this validation at the beginning or at the end of
      -
      9943  // this function, depending on what do you want to check.
      -
      9944  VMA_HEAVY_ASSERT(ValidateFreeSuballocationList());
      -
      9945 
      -
      9946  if(item->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
      -
      9947  {
      -
      9948  if(m_FreeSuballocationsBySize.empty())
      -
      9949  {
      -
      9950  m_FreeSuballocationsBySize.push_back(item);
      -
      9951  }
      -
      9952  else
      -
      9953  {
      -
      9954  VmaVectorInsertSorted<VmaSuballocationItemSizeLess>(m_FreeSuballocationsBySize, item);
      -
      9955  }
      -
      9956  }
      -
      9957 
      -
      9958  //VMA_HEAVY_ASSERT(ValidateFreeSuballocationList());
      -
      9959 }
      -
      9960 
      -
      9961 
      -
      9962 void VmaBlockMetadata_Generic::UnregisterFreeSuballocation(VmaSuballocationList::iterator item)
      -
      9963 {
      -
      9964  VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
      -
      9965  VMA_ASSERT(item->size > 0);
      -
      9966 
      -
      9967  // You may want to enable this validation at the beginning or at the end of
      -
      9968  // this function, depending on what do you want to check.
      -
      9969  VMA_HEAVY_ASSERT(ValidateFreeSuballocationList());
      -
      9970 
      -
      9971  if(item->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
      -
      9972  {
      -
      9973  VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess(
      -
      9974  m_FreeSuballocationsBySize.data(),
      -
      9975  m_FreeSuballocationsBySize.data() + m_FreeSuballocationsBySize.size(),
      -
      9976  item,
      -
      9977  VmaSuballocationItemSizeLess());
      -
      9978  for(size_t index = it - m_FreeSuballocationsBySize.data();
      -
      9979  index < m_FreeSuballocationsBySize.size();
      -
      9980  ++index)
      -
      9981  {
      -
      9982  if(m_FreeSuballocationsBySize[index] == item)
      -
      9983  {
      -
      9984  VmaVectorRemove(m_FreeSuballocationsBySize, index);
      -
      9985  return;
      -
      9986  }
      -
      9987  VMA_ASSERT((m_FreeSuballocationsBySize[index]->size == item->size) && "Not found.");
      -
      9988  }
      -
      9989  VMA_ASSERT(0 && "Not found.");
      -
      9990  }
      -
      9991 
      -
      9992  //VMA_HEAVY_ASSERT(ValidateFreeSuballocationList());
      -
      9993 }
      -
      9994 
      -
      9995 bool VmaBlockMetadata_Generic::IsBufferImageGranularityConflictPossible(
      -
      9996  VkDeviceSize bufferImageGranularity,
      -
      9997  VmaSuballocationType& inOutPrevSuballocType) const
      -
      9998 {
      -
      9999  if(bufferImageGranularity == 1 || IsEmpty())
      -
      10000  {
      -
      10001  return false;
      -
      10002  }
      -
      10003 
      -
      10004  VkDeviceSize minAlignment = VK_WHOLE_SIZE;
      -
      10005  bool typeConflictFound = false;
      -
      10006  for(VmaSuballocationList::const_iterator it = m_Suballocations.cbegin();
      -
      10007  it != m_Suballocations.cend();
      -
      10008  ++it)
      -
      10009  {
      -
      10010  const VmaSuballocationType suballocType = it->type;
      -
      10011  if(suballocType != VMA_SUBALLOCATION_TYPE_FREE)
      -
      10012  {
      -
      10013  minAlignment = VMA_MIN(minAlignment, it->hAllocation->GetAlignment());
      -
      10014  if(VmaIsBufferImageGranularityConflict(inOutPrevSuballocType, suballocType))
      -
      10015  {
      -
      10016  typeConflictFound = true;
      -
      10017  }
      -
      10018  inOutPrevSuballocType = suballocType;
      -
      10019  }
      -
      10020  }
      -
      10021 
      -
      10022  return typeConflictFound || minAlignment >= bufferImageGranularity;
      -
      10023 }
      +
      9900  // Check previous suballocations for BufferImageGranularity conflicts.
      +
      9901  // Make bigger alignment if necessary.
      +
      9902  if(bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment)
      +
      9903  {
      +
      9904  bool bufferImageGranularityConflict = false;
      +
      9905  VmaSuballocationList::const_iterator prevSuballocItem = suballocItem;
      +
      9906  while(prevSuballocItem != m_Suballocations.cbegin())
      +
      9907  {
      +
      9908  --prevSuballocItem;
      +
      9909  const VmaSuballocation& prevSuballoc = *prevSuballocItem;
      +
      9910  if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, *pOffset, bufferImageGranularity))
      +
      9911  {
      +
      9912  if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType))
      +
      9913  {
      +
      9914  bufferImageGranularityConflict = true;
      +
      9915  break;
      +
      9916  }
      +
      9917  }
      +
      9918  else
      +
      9919  // Already on previous page.
      +
      9920  break;
      +
      9921  }
      +
      9922  if(bufferImageGranularityConflict)
      +
      9923  {
      +
      9924  *pOffset = VmaAlignUp(*pOffset, bufferImageGranularity);
      +
      9925  }
      +
      9926  }
      +
      9927 
      +
      9928  // Now that we have final *pOffset, check if we are past suballocItem.
      +
      9929  // If yes, return false - this function should be called for another suballocItem as starting point.
      +
      9930  if(*pOffset >= suballocItem->offset + suballocItem->size)
      +
      9931  {
      +
      9932  return false;
      +
      9933  }
      +
      9934 
      +
      9935  // Calculate padding at the beginning based on current offset.
      +
      9936  const VkDeviceSize paddingBegin = *pOffset - suballocItem->offset;
      +
      9937 
      +
      9938  // Calculate required margin at the end.
      +
      9939  const VkDeviceSize requiredEndMargin = VMA_DEBUG_MARGIN;
      +
      9940 
      +
      9941  const VkDeviceSize totalSize = paddingBegin + allocSize + requiredEndMargin;
      +
      9942  // Another early return check.
      +
      9943  if(suballocItem->offset + totalSize > GetSize())
      +
      9944  {
      +
      9945  return false;
      +
      9946  }
      +
      9947 
      +
      9948  // Advance lastSuballocItem until desired size is reached.
      +
      9949  // Update itemsToMakeLostCount.
      +
      9950  VmaSuballocationList::const_iterator lastSuballocItem = suballocItem;
      +
      9951  if(totalSize > suballocItem->size)
      +
      9952  {
      +
      9953  VkDeviceSize remainingSize = totalSize - suballocItem->size;
      +
      9954  while(remainingSize > 0)
      +
      9955  {
      +
      9956  ++lastSuballocItem;
      +
      9957  if(lastSuballocItem == m_Suballocations.cend())
      +
      9958  {
      +
      9959  return false;
      +
      9960  }
      +
      9961  if(lastSuballocItem->type == VMA_SUBALLOCATION_TYPE_FREE)
      +
      9962  {
      +
      9963  *pSumFreeSize += lastSuballocItem->size;
      +
      9964  }
      +
      9965  else
      +
      9966  {
      +
      9967  VMA_ASSERT(lastSuballocItem->hAllocation != VK_NULL_HANDLE);
      +
      9968  if(lastSuballocItem->hAllocation->CanBecomeLost() &&
      +
      9969  lastSuballocItem->hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
      +
      9970  {
      +
      9971  ++*itemsToMakeLostCount;
      +
      9972  *pSumItemSize += lastSuballocItem->size;
      +
      9973  }
      +
      9974  else
      +
      9975  {
      +
      9976  return false;
      +
      9977  }
      +
      9978  }
      +
      9979  remainingSize = (lastSuballocItem->size < remainingSize) ?
      +
      9980  remainingSize - lastSuballocItem->size : 0;
      +
      9981  }
      +
      9982  }
      +
      9983 
      +
      9984  // Check next suballocations for BufferImageGranularity conflicts.
      +
      9985  // If conflict exists, we must mark more allocations lost or fail.
      +
      9986  if(allocSize % bufferImageGranularity || *pOffset % bufferImageGranularity)
      +
      9987  {
      +
      9988  VmaSuballocationList::const_iterator nextSuballocItem = lastSuballocItem;
      +
      9989  ++nextSuballocItem;
      +
      9990  while(nextSuballocItem != m_Suballocations.cend())
      +
      9991  {
      +
      9992  const VmaSuballocation& nextSuballoc = *nextSuballocItem;
      +
      9993  if(VmaBlocksOnSamePage(*pOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
      +
      9994  {
      +
      9995  if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type))
      +
      9996  {
      +
      9997  VMA_ASSERT(nextSuballoc.hAllocation != VK_NULL_HANDLE);
      +
      9998  if(nextSuballoc.hAllocation->CanBecomeLost() &&
      +
      9999  nextSuballoc.hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
      +
      10000  {
      +
      10001  ++*itemsToMakeLostCount;
      +
      10002  }
      +
      10003  else
      +
      10004  {
      +
      10005  return false;
      +
      10006  }
      +
      10007  }
      +
      10008  }
      +
      10009  else
      +
      10010  {
      +
      10011  // Already on next page.
      +
      10012  break;
      +
      10013  }
      +
      10014  ++nextSuballocItem;
      +
      10015  }
      +
      10016  }
      +
      10017  }
      +
      10018  else
      +
      10019  {
      +
      10020  const VmaSuballocation& suballoc = *suballocItem;
      +
      10021  VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
      +
      10022 
      +
      10023  *pSumFreeSize = suballoc.size;
      10024 
      -
      10026 // class VmaBlockMetadata_Linear
      -
      10027 
      -
      10028 VmaBlockMetadata_Linear::VmaBlockMetadata_Linear(VmaAllocator hAllocator) :
      -
      10029  VmaBlockMetadata(hAllocator),
      -
      10030  m_SumFreeSize(0),
      -
      10031  m_Suballocations0(VmaStlAllocator<VmaSuballocation>(hAllocator->GetAllocationCallbacks())),
      -
      10032  m_Suballocations1(VmaStlAllocator<VmaSuballocation>(hAllocator->GetAllocationCallbacks())),
      -
      10033  m_1stVectorIndex(0),
      -
      10034  m_2ndVectorMode(SECOND_VECTOR_EMPTY),
      -
      10035  m_1stNullItemsBeginCount(0),
      -
      10036  m_1stNullItemsMiddleCount(0),
      -
      10037  m_2ndNullItemsCount(0)
      -
      10038 {
      -
      10039 }
      -
      10040 
      -
      10041 VmaBlockMetadata_Linear::~VmaBlockMetadata_Linear()
      -
      10042 {
      -
      10043 }
      -
      10044 
      -
      10045 void VmaBlockMetadata_Linear::Init(VkDeviceSize size)
      -
      10046 {
      -
      10047  VmaBlockMetadata::Init(size);
      -
      10048  m_SumFreeSize = size;
      -
      10049 }
      -
      10050 
      -
      10051 bool VmaBlockMetadata_Linear::Validate() const
      -
      10052 {
      -
      10053  const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      -
      10054  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      -
      10055 
      -
      10056  VMA_VALIDATE(suballocations2nd.empty() == (m_2ndVectorMode == SECOND_VECTOR_EMPTY));
      -
      10057  VMA_VALIDATE(!suballocations1st.empty() ||
      -
      10058  suballocations2nd.empty() ||
      -
      10059  m_2ndVectorMode != SECOND_VECTOR_RING_BUFFER);
      -
      10060 
      -
      10061  if(!suballocations1st.empty())
      -
      10062  {
      -
      10063  // Null item at the beginning should be accounted into m_1stNullItemsBeginCount.
      -
      10064  VMA_VALIDATE(suballocations1st[m_1stNullItemsBeginCount].hAllocation != VK_NULL_HANDLE);
      -
      10065  // Null item at the end should be just pop_back().
      -
      10066  VMA_VALIDATE(suballocations1st.back().hAllocation != VK_NULL_HANDLE);
      -
      10067  }
      -
      10068  if(!suballocations2nd.empty())
      -
      10069  {
      -
      10070  // Null item at the end should be just pop_back().
      -
      10071  VMA_VALIDATE(suballocations2nd.back().hAllocation != VK_NULL_HANDLE);
      -
      10072  }
      +
      10025  // Size of this suballocation is too small for this request: Early return.
      +
      10026  if(suballoc.size < allocSize)
      +
      10027  {
      +
      10028  return false;
      +
      10029  }
      +
      10030 
      +
      10031  // Start from offset equal to beginning of this suballocation.
      +
      10032  *pOffset = suballoc.offset;
      +
      10033 
      +
      10034  // Apply VMA_DEBUG_MARGIN at the beginning.
      +
      10035  if(VMA_DEBUG_MARGIN > 0)
      +
      10036  {
      +
      10037  *pOffset += VMA_DEBUG_MARGIN;
      +
      10038  }
      +
      10039 
      +
      10040  // Apply alignment.
      +
      10041  *pOffset = VmaAlignUp(*pOffset, allocAlignment);
      +
      10042 
      +
      10043  // Check previous suballocations for BufferImageGranularity conflicts.
      +
      10044  // Make bigger alignment if necessary.
      +
      10045  if(bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment)
      +
      10046  {
      +
      10047  bool bufferImageGranularityConflict = false;
      +
      10048  VmaSuballocationList::const_iterator prevSuballocItem = suballocItem;
      +
      10049  while(prevSuballocItem != m_Suballocations.cbegin())
      +
      10050  {
      +
      10051  --prevSuballocItem;
      +
      10052  const VmaSuballocation& prevSuballoc = *prevSuballocItem;
      +
      10053  if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, *pOffset, bufferImageGranularity))
      +
      10054  {
      +
      10055  if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType))
      +
      10056  {
      +
      10057  bufferImageGranularityConflict = true;
      +
      10058  break;
      +
      10059  }
      +
      10060  }
      +
      10061  else
      +
      10062  // Already on previous page.
      +
      10063  break;
      +
      10064  }
      +
      10065  if(bufferImageGranularityConflict)
      +
      10066  {
      +
      10067  *pOffset = VmaAlignUp(*pOffset, bufferImageGranularity);
      +
      10068  }
      +
      10069  }
      +
      10070 
      +
      10071  // Calculate padding at the beginning based on current offset.
      +
      10072  const VkDeviceSize paddingBegin = *pOffset - suballoc.offset;
      10073 
      -
      10074  VMA_VALIDATE(m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount <= suballocations1st.size());
      -
      10075  VMA_VALIDATE(m_2ndNullItemsCount <= suballocations2nd.size());
      +
      10074  // Calculate required margin at the end.
      +
      10075  const VkDeviceSize requiredEndMargin = VMA_DEBUG_MARGIN;
      10076 
      -
      10077  VkDeviceSize sumUsedSize = 0;
      -
      10078  const size_t suballoc1stCount = suballocations1st.size();
      -
      10079  VkDeviceSize offset = VMA_DEBUG_MARGIN;
      -
      10080 
      -
      10081  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
      -
      10082  {
      -
      10083  const size_t suballoc2ndCount = suballocations2nd.size();
      -
      10084  size_t nullItem2ndCount = 0;
      -
      10085  for(size_t i = 0; i < suballoc2ndCount; ++i)
      +
      10077  // Fail if requested size plus margin before and after is bigger than size of this suballocation.
      +
      10078  if(paddingBegin + allocSize + requiredEndMargin > suballoc.size)
      +
      10079  {
      +
      10080  return false;
      +
      10081  }
      +
      10082 
      +
      10083  // Check next suballocations for BufferImageGranularity conflicts.
      +
      10084  // If conflict exists, allocation cannot be made here.
      +
      10085  if(allocSize % bufferImageGranularity || *pOffset % bufferImageGranularity)
      10086  {
      -
      10087  const VmaSuballocation& suballoc = suballocations2nd[i];
      -
      10088  const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
      -
      10089 
      -
      10090  VMA_VALIDATE(currFree == (suballoc.hAllocation == VK_NULL_HANDLE));
      -
      10091  VMA_VALIDATE(suballoc.offset >= offset);
      -
      10092 
      -
      10093  if(!currFree)
      -
      10094  {
      -
      10095  VMA_VALIDATE(suballoc.hAllocation->GetOffset() == suballoc.offset);
      -
      10096  VMA_VALIDATE(suballoc.hAllocation->GetSize() == suballoc.size);
      -
      10097  sumUsedSize += suballoc.size;
      -
      10098  }
      -
      10099  else
      -
      10100  {
      -
      10101  ++nullItem2ndCount;
      -
      10102  }
      -
      10103 
      -
      10104  offset = suballoc.offset + suballoc.size + VMA_DEBUG_MARGIN;
      -
      10105  }
      -
      10106 
      -
      10107  VMA_VALIDATE(nullItem2ndCount == m_2ndNullItemsCount);
      -
      10108  }
      -
      10109 
      -
      10110  for(size_t i = 0; i < m_1stNullItemsBeginCount; ++i)
      -
      10111  {
      -
      10112  const VmaSuballocation& suballoc = suballocations1st[i];
      -
      10113  VMA_VALIDATE(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE &&
      -
      10114  suballoc.hAllocation == VK_NULL_HANDLE);
      -
      10115  }
      -
      10116 
      -
      10117  size_t nullItem1stCount = m_1stNullItemsBeginCount;
      -
      10118 
      -
      10119  for(size_t i = m_1stNullItemsBeginCount; i < suballoc1stCount; ++i)
      -
      10120  {
      -
      10121  const VmaSuballocation& suballoc = suballocations1st[i];
      -
      10122  const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
      -
      10123 
      -
      10124  VMA_VALIDATE(currFree == (suballoc.hAllocation == VK_NULL_HANDLE));
      -
      10125  VMA_VALIDATE(suballoc.offset >= offset);
      -
      10126  VMA_VALIDATE(i >= m_1stNullItemsBeginCount || currFree);
      +
      10087  VmaSuballocationList::const_iterator nextSuballocItem = suballocItem;
      +
      10088  ++nextSuballocItem;
      +
      10089  while(nextSuballocItem != m_Suballocations.cend())
      +
      10090  {
      +
      10091  const VmaSuballocation& nextSuballoc = *nextSuballocItem;
      +
      10092  if(VmaBlocksOnSamePage(*pOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
      +
      10093  {
      +
      10094  if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type))
      +
      10095  {
      +
      10096  return false;
      +
      10097  }
      +
      10098  }
      +
      10099  else
      +
      10100  {
      +
      10101  // Already on next page.
      +
      10102  break;
      +
      10103  }
      +
      10104  ++nextSuballocItem;
      +
      10105  }
      +
      10106  }
      +
      10107  }
      +
      10108 
      +
      10109  // All tests passed: Success. pOffset is already filled.
      +
      10110  return true;
      +
      10111 }
      +
      10112 
      +
      10113 void VmaBlockMetadata_Generic::MergeFreeWithNext(VmaSuballocationList::iterator item)
      +
      10114 {
      +
      10115  VMA_ASSERT(item != m_Suballocations.end());
      +
      10116  VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
      +
      10117 
      +
      10118  VmaSuballocationList::iterator nextItem = item;
      +
      10119  ++nextItem;
      +
      10120  VMA_ASSERT(nextItem != m_Suballocations.end());
      +
      10121  VMA_ASSERT(nextItem->type == VMA_SUBALLOCATION_TYPE_FREE);
      +
      10122 
      +
      10123  item->size += nextItem->size;
      +
      10124  --m_FreeCount;
      +
      10125  m_Suballocations.erase(nextItem);
      +
      10126 }
      10127 
      -
      10128  if(!currFree)
      -
      10129  {
      -
      10130  VMA_VALIDATE(suballoc.hAllocation->GetOffset() == suballoc.offset);
      -
      10131  VMA_VALIDATE(suballoc.hAllocation->GetSize() == suballoc.size);
      -
      10132  sumUsedSize += suballoc.size;
      -
      10133  }
      -
      10134  else
      -
      10135  {
      -
      10136  ++nullItem1stCount;
      -
      10137  }
      +
      10128 VmaSuballocationList::iterator VmaBlockMetadata_Generic::FreeSuballocation(VmaSuballocationList::iterator suballocItem)
      +
      10129 {
      +
      10130  // Change this suballocation to be marked as free.
      +
      10131  VmaSuballocation& suballoc = *suballocItem;
      +
      10132  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
      +
      10133  suballoc.hAllocation = VK_NULL_HANDLE;
      +
      10134 
      +
      10135  // Update totals.
      +
      10136  ++m_FreeCount;
      +
      10137  m_SumFreeSize += suballoc.size;
      10138 
      -
      10139  offset = suballoc.offset + suballoc.size + VMA_DEBUG_MARGIN;
      -
      10140  }
      -
      10141  VMA_VALIDATE(nullItem1stCount == m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount);
      +
      10139  // Merge with previous and/or next suballocation if it's also free.
      +
      10140  bool mergeWithNext = false;
      +
      10141  bool mergeWithPrev = false;
      10142 
      -
      10143  if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
      -
      10144  {
      -
      10145  const size_t suballoc2ndCount = suballocations2nd.size();
      -
      10146  size_t nullItem2ndCount = 0;
      -
      10147  for(size_t i = suballoc2ndCount; i--; )
      -
      10148  {
      -
      10149  const VmaSuballocation& suballoc = suballocations2nd[i];
      -
      10150  const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
      -
      10151 
      -
      10152  VMA_VALIDATE(currFree == (suballoc.hAllocation == VK_NULL_HANDLE));
      -
      10153  VMA_VALIDATE(suballoc.offset >= offset);
      -
      10154 
      -
      10155  if(!currFree)
      -
      10156  {
      -
      10157  VMA_VALIDATE(suballoc.hAllocation->GetOffset() == suballoc.offset);
      -
      10158  VMA_VALIDATE(suballoc.hAllocation->GetSize() == suballoc.size);
      -
      10159  sumUsedSize += suballoc.size;
      -
      10160  }
      -
      10161  else
      -
      10162  {
      -
      10163  ++nullItem2ndCount;
      -
      10164  }
      +
      10143  VmaSuballocationList::iterator nextItem = suballocItem;
      +
      10144  ++nextItem;
      +
      10145  if((nextItem != m_Suballocations.end()) && (nextItem->type == VMA_SUBALLOCATION_TYPE_FREE))
      +
      10146  {
      +
      10147  mergeWithNext = true;
      +
      10148  }
      +
      10149 
      +
      10150  VmaSuballocationList::iterator prevItem = suballocItem;
      +
      10151  if(suballocItem != m_Suballocations.begin())
      +
      10152  {
      +
      10153  --prevItem;
      +
      10154  if(prevItem->type == VMA_SUBALLOCATION_TYPE_FREE)
      +
      10155  {
      +
      10156  mergeWithPrev = true;
      +
      10157  }
      +
      10158  }
      +
      10159 
      +
      10160  if(mergeWithNext)
      +
      10161  {
      +
      10162  UnregisterFreeSuballocation(nextItem);
      +
      10163  MergeFreeWithNext(suballocItem);
      +
      10164  }
      10165 
      -
      10166  offset = suballoc.offset + suballoc.size + VMA_DEBUG_MARGIN;
      -
      10167  }
      -
      10168 
      -
      10169  VMA_VALIDATE(nullItem2ndCount == m_2ndNullItemsCount);
      -
      10170  }
      -
      10171 
      -
      10172  VMA_VALIDATE(offset <= GetSize());
      -
      10173  VMA_VALIDATE(m_SumFreeSize == GetSize() - sumUsedSize);
      -
      10174 
      -
      10175  return true;
      -
      10176 }
      -
      10177 
      -
      10178 size_t VmaBlockMetadata_Linear::GetAllocationCount() const
      -
      10179 {
      -
      10180  return AccessSuballocations1st().size() - (m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount) +
      -
      10181  AccessSuballocations2nd().size() - m_2ndNullItemsCount;
      -
      10182 }
      -
      10183 
      -
      10184 VkDeviceSize VmaBlockMetadata_Linear::GetUnusedRangeSizeMax() const
      -
      10185 {
      -
      10186  const VkDeviceSize size = GetSize();
      -
      10187 
      -
      10188  /*
      -
      10189  We don't consider gaps inside allocation vectors with freed allocations because
      -
      10190  they are not suitable for reuse in linear allocator. We consider only space that
      -
      10191  is available for new allocations.
      -
      10192  */
      -
      10193  if(IsEmpty())
      -
      10194  {
      -
      10195  return size;
      -
      10196  }
      -
      10197 
      -
      10198  const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      -
      10199 
      -
      10200  switch(m_2ndVectorMode)
      -
      10201  {
      -
      10202  case SECOND_VECTOR_EMPTY:
      -
      10203  /*
      -
      10204  Available space is after end of 1st, as well as before beginning of 1st (which
      -
      10205  whould make it a ring buffer).
      -
      10206  */
      -
      10207  {
      -
      10208  const size_t suballocations1stCount = suballocations1st.size();
      -
      10209  VMA_ASSERT(suballocations1stCount > m_1stNullItemsBeginCount);
      -
      10210  const VmaSuballocation& firstSuballoc = suballocations1st[m_1stNullItemsBeginCount];
      -
      10211  const VmaSuballocation& lastSuballoc = suballocations1st[suballocations1stCount - 1];
      -
      10212  return VMA_MAX(
      -
      10213  firstSuballoc.offset,
      -
      10214  size - (lastSuballoc.offset + lastSuballoc.size));
      -
      10215  }
      -
      10216  break;
      -
      10217 
      -
      10218  case SECOND_VECTOR_RING_BUFFER:
      -
      10219  /*
      -
      10220  Available space is only between end of 2nd and beginning of 1st.
      -
      10221  */
      -
      10222  {
      -
      10223  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      -
      10224  const VmaSuballocation& lastSuballoc2nd = suballocations2nd.back();
      -
      10225  const VmaSuballocation& firstSuballoc1st = suballocations1st[m_1stNullItemsBeginCount];
      -
      10226  return firstSuballoc1st.offset - (lastSuballoc2nd.offset + lastSuballoc2nd.size);
      -
      10227  }
      -
      10228  break;
      -
      10229 
      -
      10230  case SECOND_VECTOR_DOUBLE_STACK:
      -
      10231  /*
      -
      10232  Available space is only between end of 1st and top of 2nd.
      -
      10233  */
      -
      10234  {
      -
      10235  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      -
      10236  const VmaSuballocation& topSuballoc2nd = suballocations2nd.back();
      -
      10237  const VmaSuballocation& lastSuballoc1st = suballocations1st.back();
      -
      10238  return topSuballoc2nd.offset - (lastSuballoc1st.offset + lastSuballoc1st.size);
      -
      10239  }
      -
      10240  break;
      -
      10241 
      -
      10242  default:
      -
      10243  VMA_ASSERT(0);
      -
      10244  return 0;
      +
      10166  if(mergeWithPrev)
      +
      10167  {
      +
      10168  UnregisterFreeSuballocation(prevItem);
      +
      10169  MergeFreeWithNext(prevItem);
      +
      10170  RegisterFreeSuballocation(prevItem);
      +
      10171  return prevItem;
      +
      10172  }
      +
      10173  else
      +
      10174  {
      +
      10175  RegisterFreeSuballocation(suballocItem);
      +
      10176  return suballocItem;
      +
      10177  }
      +
      10178 }
      +
      10179 
      +
      10180 void VmaBlockMetadata_Generic::RegisterFreeSuballocation(VmaSuballocationList::iterator item)
      +
      10181 {
      +
      10182  VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
      +
      10183  VMA_ASSERT(item->size > 0);
      +
      10184 
      +
      10185  // You may want to enable this validation at the beginning or at the end of
      +
      10186  // this function, depending on what do you want to check.
      +
      10187  VMA_HEAVY_ASSERT(ValidateFreeSuballocationList());
      +
      10188 
      +
      10189  if(item->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
      +
      10190  {
      +
      10191  if(m_FreeSuballocationsBySize.empty())
      +
      10192  {
      +
      10193  m_FreeSuballocationsBySize.push_back(item);
      +
      10194  }
      +
      10195  else
      +
      10196  {
      +
      10197  VmaVectorInsertSorted<VmaSuballocationItemSizeLess>(m_FreeSuballocationsBySize, item);
      +
      10198  }
      +
      10199  }
      +
      10200 
      +
      10201  //VMA_HEAVY_ASSERT(ValidateFreeSuballocationList());
      +
      10202 }
      +
      10203 
      +
      10204 
      +
      10205 void VmaBlockMetadata_Generic::UnregisterFreeSuballocation(VmaSuballocationList::iterator item)
      +
      10206 {
      +
      10207  VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
      +
      10208  VMA_ASSERT(item->size > 0);
      +
      10209 
      +
      10210  // You may want to enable this validation at the beginning or at the end of
      +
      10211  // this function, depending on what do you want to check.
      +
      10212  VMA_HEAVY_ASSERT(ValidateFreeSuballocationList());
      +
      10213 
      +
      10214  if(item->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
      +
      10215  {
      +
      10216  VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess(
      +
      10217  m_FreeSuballocationsBySize.data(),
      +
      10218  m_FreeSuballocationsBySize.data() + m_FreeSuballocationsBySize.size(),
      +
      10219  item,
      +
      10220  VmaSuballocationItemSizeLess());
      +
      10221  for(size_t index = it - m_FreeSuballocationsBySize.data();
      +
      10222  index < m_FreeSuballocationsBySize.size();
      +
      10223  ++index)
      +
      10224  {
      +
      10225  if(m_FreeSuballocationsBySize[index] == item)
      +
      10226  {
      +
      10227  VmaVectorRemove(m_FreeSuballocationsBySize, index);
      +
      10228  return;
      +
      10229  }
      +
      10230  VMA_ASSERT((m_FreeSuballocationsBySize[index]->size == item->size) && "Not found.");
      +
      10231  }
      +
      10232  VMA_ASSERT(0 && "Not found.");
      +
      10233  }
      +
      10234 
      +
      10235  //VMA_HEAVY_ASSERT(ValidateFreeSuballocationList());
      +
      10236 }
      +
      10237 
      +
      10238 bool VmaBlockMetadata_Generic::IsBufferImageGranularityConflictPossible(
      +
      10239  VkDeviceSize bufferImageGranularity,
      +
      10240  VmaSuballocationType& inOutPrevSuballocType) const
      +
      10241 {
      +
      10242  if(bufferImageGranularity == 1 || IsEmpty())
      +
      10243  {
      +
      10244  return false;
      10245  }
      -
      10246 }
      -
      10247 
      -
      10248 void VmaBlockMetadata_Linear::CalcAllocationStatInfo(VmaStatInfo& outInfo) const
      -
      10249 {
      -
      10250  const VkDeviceSize size = GetSize();
      -
      10251  const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      -
      10252  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      -
      10253  const size_t suballoc1stCount = suballocations1st.size();
      -
      10254  const size_t suballoc2ndCount = suballocations2nd.size();
      -
      10255 
      -
      10256  outInfo.blockCount = 1;
      -
      10257  outInfo.allocationCount = (uint32_t)GetAllocationCount();
      -
      10258  outInfo.unusedRangeCount = 0;
      -
      10259  outInfo.usedBytes = 0;
      -
      10260  outInfo.allocationSizeMin = UINT64_MAX;
      -
      10261  outInfo.allocationSizeMax = 0;
      -
      10262  outInfo.unusedRangeSizeMin = UINT64_MAX;
      -
      10263  outInfo.unusedRangeSizeMax = 0;
      +
      10246 
      +
      10247  VkDeviceSize minAlignment = VK_WHOLE_SIZE;
      +
      10248  bool typeConflictFound = false;
      +
      10249  for(VmaSuballocationList::const_iterator it = m_Suballocations.cbegin();
      +
      10250  it != m_Suballocations.cend();
      +
      10251  ++it)
      +
      10252  {
      +
      10253  const VmaSuballocationType suballocType = it->type;
      +
      10254  if(suballocType != VMA_SUBALLOCATION_TYPE_FREE)
      +
      10255  {
      +
      10256  minAlignment = VMA_MIN(minAlignment, it->hAllocation->GetAlignment());
      +
      10257  if(VmaIsBufferImageGranularityConflict(inOutPrevSuballocType, suballocType))
      +
      10258  {
      +
      10259  typeConflictFound = true;
      +
      10260  }
      +
      10261  inOutPrevSuballocType = suballocType;
      +
      10262  }
      +
      10263  }
      10264 
      -
      10265  VkDeviceSize lastOffset = 0;
      -
      10266 
      -
      10267  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
      -
      10268  {
      -
      10269  const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
      -
      10270  size_t nextAlloc2ndIndex = 0;
      -
      10271  while(lastOffset < freeSpace2ndTo1stEnd)
      -
      10272  {
      -
      10273  // Find next non-null allocation or move nextAllocIndex to the end.
      -
      10274  while(nextAlloc2ndIndex < suballoc2ndCount &&
      -
      10275  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
      -
      10276  {
      -
      10277  ++nextAlloc2ndIndex;
      -
      10278  }
      -
      10279 
      -
      10280  // Found non-null allocation.
      -
      10281  if(nextAlloc2ndIndex < suballoc2ndCount)
      -
      10282  {
      -
      10283  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
      -
      10284 
      -
      10285  // 1. Process free space before this allocation.
      -
      10286  if(lastOffset < suballoc.offset)
      -
      10287  {
      -
      10288  // There is free space from lastOffset to suballoc.offset.
      -
      10289  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
      -
      10290  ++outInfo.unusedRangeCount;
      -
      10291  outInfo.unusedBytes += unusedRangeSize;
      -
      10292  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
      -
      10293  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
      -
      10294  }
      -
      10295 
      -
      10296  // 2. Process this allocation.
      -
      10297  // There is allocation with suballoc.offset, suballoc.size.
      -
      10298  outInfo.usedBytes += suballoc.size;
      -
      10299  outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size);
      -
      10300  outInfo.allocationSizeMax = VMA_MIN(outInfo.allocationSizeMax, suballoc.size);
      -
      10301 
      -
      10302  // 3. Prepare for next iteration.
      -
      10303  lastOffset = suballoc.offset + suballoc.size;
      -
      10304  ++nextAlloc2ndIndex;
      -
      10305  }
      -
      10306  // We are at the end.
      -
      10307  else
      -
      10308  {
      -
      10309  // There is free space from lastOffset to freeSpace2ndTo1stEnd.
      -
      10310  if(lastOffset < freeSpace2ndTo1stEnd)
      -
      10311  {
      -
      10312  const VkDeviceSize unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset;
      -
      10313  ++outInfo.unusedRangeCount;
      -
      10314  outInfo.unusedBytes += unusedRangeSize;
      -
      10315  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
      -
      10316  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
      -
      10317  }
      -
      10318 
      -
      10319  // End of loop.
      -
      10320  lastOffset = freeSpace2ndTo1stEnd;
      -
      10321  }
      -
      10322  }
      -
      10323  }
      -
      10324 
      -
      10325  size_t nextAlloc1stIndex = m_1stNullItemsBeginCount;
      -
      10326  const VkDeviceSize freeSpace1stTo2ndEnd =
      -
      10327  m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size;
      -
      10328  while(lastOffset < freeSpace1stTo2ndEnd)
      -
      10329  {
      -
      10330  // Find next non-null allocation or move nextAllocIndex to the end.
      -
      10331  while(nextAlloc1stIndex < suballoc1stCount &&
      -
      10332  suballocations1st[nextAlloc1stIndex].hAllocation == VK_NULL_HANDLE)
      -
      10333  {
      -
      10334  ++nextAlloc1stIndex;
      -
      10335  }
      -
      10336 
      -
      10337  // Found non-null allocation.
      -
      10338  if(nextAlloc1stIndex < suballoc1stCount)
      -
      10339  {
      -
      10340  const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex];
      -
      10341 
      -
      10342  // 1. Process free space before this allocation.
      -
      10343  if(lastOffset < suballoc.offset)
      -
      10344  {
      -
      10345  // There is free space from lastOffset to suballoc.offset.
      -
      10346  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
      -
      10347  ++outInfo.unusedRangeCount;
      -
      10348  outInfo.unusedBytes += unusedRangeSize;
      -
      10349  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
      -
      10350  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
      -
      10351  }
      +
      10265  return typeConflictFound || minAlignment >= bufferImageGranularity;
      +
      10266 }
      +
      10267 
      +
      10269 // class VmaBlockMetadata_Linear
      +
      10270 
      +
      10271 VmaBlockMetadata_Linear::VmaBlockMetadata_Linear(VmaAllocator hAllocator) :
      +
      10272  VmaBlockMetadata(hAllocator),
      +
      10273  m_SumFreeSize(0),
      +
      10274  m_Suballocations0(VmaStlAllocator<VmaSuballocation>(hAllocator->GetAllocationCallbacks())),
      +
      10275  m_Suballocations1(VmaStlAllocator<VmaSuballocation>(hAllocator->GetAllocationCallbacks())),
      +
      10276  m_1stVectorIndex(0),
      +
      10277  m_2ndVectorMode(SECOND_VECTOR_EMPTY),
      +
      10278  m_1stNullItemsBeginCount(0),
      +
      10279  m_1stNullItemsMiddleCount(0),
      +
      10280  m_2ndNullItemsCount(0)
      +
      10281 {
      +
      10282 }
      +
      10283 
      +
      10284 VmaBlockMetadata_Linear::~VmaBlockMetadata_Linear()
      +
      10285 {
      +
      10286 }
      +
      10287 
      +
      10288 void VmaBlockMetadata_Linear::Init(VkDeviceSize size)
      +
      10289 {
      +
      10290  VmaBlockMetadata::Init(size);
      +
      10291  m_SumFreeSize = size;
      +
      10292 }
      +
      10293 
      +
      10294 bool VmaBlockMetadata_Linear::Validate() const
      +
      10295 {
      +
      10296  const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      +
      10297  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      +
      10298 
      +
      10299  VMA_VALIDATE(suballocations2nd.empty() == (m_2ndVectorMode == SECOND_VECTOR_EMPTY));
      +
      10300  VMA_VALIDATE(!suballocations1st.empty() ||
      +
      10301  suballocations2nd.empty() ||
      +
      10302  m_2ndVectorMode != SECOND_VECTOR_RING_BUFFER);
      +
      10303 
      +
      10304  if(!suballocations1st.empty())
      +
      10305  {
      +
      10306  // Null item at the beginning should be accounted into m_1stNullItemsBeginCount.
      +
      10307  VMA_VALIDATE(suballocations1st[m_1stNullItemsBeginCount].hAllocation != VK_NULL_HANDLE);
      +
      10308  // Null item at the end should be just pop_back().
      +
      10309  VMA_VALIDATE(suballocations1st.back().hAllocation != VK_NULL_HANDLE);
      +
      10310  }
      +
      10311  if(!suballocations2nd.empty())
      +
      10312  {
      +
      10313  // Null item at the end should be just pop_back().
      +
      10314  VMA_VALIDATE(suballocations2nd.back().hAllocation != VK_NULL_HANDLE);
      +
      10315  }
      +
      10316 
      +
      10317  VMA_VALIDATE(m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount <= suballocations1st.size());
      +
      10318  VMA_VALIDATE(m_2ndNullItemsCount <= suballocations2nd.size());
      +
      10319 
      +
      10320  VkDeviceSize sumUsedSize = 0;
      +
      10321  const size_t suballoc1stCount = suballocations1st.size();
      +
      10322  VkDeviceSize offset = VMA_DEBUG_MARGIN;
      +
      10323 
      +
      10324  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
      +
      10325  {
      +
      10326  const size_t suballoc2ndCount = suballocations2nd.size();
      +
      10327  size_t nullItem2ndCount = 0;
      +
      10328  for(size_t i = 0; i < suballoc2ndCount; ++i)
      +
      10329  {
      +
      10330  const VmaSuballocation& suballoc = suballocations2nd[i];
      +
      10331  const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
      +
      10332 
      +
      10333  VMA_VALIDATE(currFree == (suballoc.hAllocation == VK_NULL_HANDLE));
      +
      10334  VMA_VALIDATE(suballoc.offset >= offset);
      +
      10335 
      +
      10336  if(!currFree)
      +
      10337  {
      +
      10338  VMA_VALIDATE(suballoc.hAllocation->GetOffset() == suballoc.offset);
      +
      10339  VMA_VALIDATE(suballoc.hAllocation->GetSize() == suballoc.size);
      +
      10340  sumUsedSize += suballoc.size;
      +
      10341  }
      +
      10342  else
      +
      10343  {
      +
      10344  ++nullItem2ndCount;
      +
      10345  }
      +
      10346 
      +
      10347  offset = suballoc.offset + suballoc.size + VMA_DEBUG_MARGIN;
      +
      10348  }
      +
      10349 
      +
      10350  VMA_VALIDATE(nullItem2ndCount == m_2ndNullItemsCount);
      +
      10351  }
      10352 
      -
      10353  // 2. Process this allocation.
      -
      10354  // There is allocation with suballoc.offset, suballoc.size.
      -
      10355  outInfo.usedBytes += suballoc.size;
      -
      10356  outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size);
      -
      10357  outInfo.allocationSizeMax = VMA_MIN(outInfo.allocationSizeMax, suballoc.size);
      -
      10358 
      -
      10359  // 3. Prepare for next iteration.
      -
      10360  lastOffset = suballoc.offset + suballoc.size;
      -
      10361  ++nextAlloc1stIndex;
      -
      10362  }
      -
      10363  // We are at the end.
      -
      10364  else
      -
      10365  {
      -
      10366  // There is free space from lastOffset to freeSpace1stTo2ndEnd.
      -
      10367  if(lastOffset < freeSpace1stTo2ndEnd)
      -
      10368  {
      -
      10369  const VkDeviceSize unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset;
      -
      10370  ++outInfo.unusedRangeCount;
      -
      10371  outInfo.unusedBytes += unusedRangeSize;
      -
      10372  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
      -
      10373  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
      -
      10374  }
      -
      10375 
      -
      10376  // End of loop.
      -
      10377  lastOffset = freeSpace1stTo2ndEnd;
      -
      10378  }
      -
      10379  }
      -
      10380 
      -
      10381  if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
      -
      10382  {
      -
      10383  size_t nextAlloc2ndIndex = suballocations2nd.size() - 1;
      -
      10384  while(lastOffset < size)
      -
      10385  {
      -
      10386  // Find next non-null allocation or move nextAllocIndex to the end.
      -
      10387  while(nextAlloc2ndIndex != SIZE_MAX &&
      -
      10388  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
      -
      10389  {
      -
      10390  --nextAlloc2ndIndex;
      -
      10391  }
      -
      10392 
      -
      10393  // Found non-null allocation.
      -
      10394  if(nextAlloc2ndIndex != SIZE_MAX)
      -
      10395  {
      -
      10396  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
      +
      10353  for(size_t i = 0; i < m_1stNullItemsBeginCount; ++i)
      +
      10354  {
      +
      10355  const VmaSuballocation& suballoc = suballocations1st[i];
      +
      10356  VMA_VALIDATE(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE &&
      +
      10357  suballoc.hAllocation == VK_NULL_HANDLE);
      +
      10358  }
      +
      10359 
      +
      10360  size_t nullItem1stCount = m_1stNullItemsBeginCount;
      +
      10361 
      +
      10362  for(size_t i = m_1stNullItemsBeginCount; i < suballoc1stCount; ++i)
      +
      10363  {
      +
      10364  const VmaSuballocation& suballoc = suballocations1st[i];
      +
      10365  const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
      +
      10366 
      +
      10367  VMA_VALIDATE(currFree == (suballoc.hAllocation == VK_NULL_HANDLE));
      +
      10368  VMA_VALIDATE(suballoc.offset >= offset);
      +
      10369  VMA_VALIDATE(i >= m_1stNullItemsBeginCount || currFree);
      +
      10370 
      +
      10371  if(!currFree)
      +
      10372  {
      +
      10373  VMA_VALIDATE(suballoc.hAllocation->GetOffset() == suballoc.offset);
      +
      10374  VMA_VALIDATE(suballoc.hAllocation->GetSize() == suballoc.size);
      +
      10375  sumUsedSize += suballoc.size;
      +
      10376  }
      +
      10377  else
      +
      10378  {
      +
      10379  ++nullItem1stCount;
      +
      10380  }
      +
      10381 
      +
      10382  offset = suballoc.offset + suballoc.size + VMA_DEBUG_MARGIN;
      +
      10383  }
      +
      10384  VMA_VALIDATE(nullItem1stCount == m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount);
      +
      10385 
      +
      10386  if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
      +
      10387  {
      +
      10388  const size_t suballoc2ndCount = suballocations2nd.size();
      +
      10389  size_t nullItem2ndCount = 0;
      +
      10390  for(size_t i = suballoc2ndCount; i--; )
      +
      10391  {
      +
      10392  const VmaSuballocation& suballoc = suballocations2nd[i];
      +
      10393  const bool currFree = (suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
      +
      10394 
      +
      10395  VMA_VALIDATE(currFree == (suballoc.hAllocation == VK_NULL_HANDLE));
      +
      10396  VMA_VALIDATE(suballoc.offset >= offset);
      10397 
      -
      10398  // 1. Process free space before this allocation.
      -
      10399  if(lastOffset < suballoc.offset)
      -
      10400  {
      -
      10401  // There is free space from lastOffset to suballoc.offset.
      -
      10402  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
      -
      10403  ++outInfo.unusedRangeCount;
      -
      10404  outInfo.unusedBytes += unusedRangeSize;
      -
      10405  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
      -
      10406  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
      -
      10407  }
      +
      10398  if(!currFree)
      +
      10399  {
      +
      10400  VMA_VALIDATE(suballoc.hAllocation->GetOffset() == suballoc.offset);
      +
      10401  VMA_VALIDATE(suballoc.hAllocation->GetSize() == suballoc.size);
      +
      10402  sumUsedSize += suballoc.size;
      +
      10403  }
      +
      10404  else
      +
      10405  {
      +
      10406  ++nullItem2ndCount;
      +
      10407  }
      10408 
      -
      10409  // 2. Process this allocation.
      -
      10410  // There is allocation with suballoc.offset, suballoc.size.
      -
      10411  outInfo.usedBytes += suballoc.size;
      -
      10412  outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size);
      -
      10413  outInfo.allocationSizeMax = VMA_MIN(outInfo.allocationSizeMax, suballoc.size);
      +
      10409  offset = suballoc.offset + suballoc.size + VMA_DEBUG_MARGIN;
      +
      10410  }
      +
      10411 
      +
      10412  VMA_VALIDATE(nullItem2ndCount == m_2ndNullItemsCount);
      +
      10413  }
      10414 
      -
      10415  // 3. Prepare for next iteration.
      -
      10416  lastOffset = suballoc.offset + suballoc.size;
      -
      10417  --nextAlloc2ndIndex;
      -
      10418  }
      -
      10419  // We are at the end.
      -
      10420  else
      -
      10421  {
      -
      10422  // There is free space from lastOffset to size.
      -
      10423  if(lastOffset < size)
      -
      10424  {
      -
      10425  const VkDeviceSize unusedRangeSize = size - lastOffset;
      -
      10426  ++outInfo.unusedRangeCount;
      -
      10427  outInfo.unusedBytes += unusedRangeSize;
      -
      10428  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
      -
      10429  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
      -
      10430  }
      -
      10431 
      -
      10432  // End of loop.
      -
      10433  lastOffset = size;
      -
      10434  }
      -
      10435  }
      -
      10436  }
      -
      10437 
      -
      10438  outInfo.unusedBytes = size - outInfo.usedBytes;
      -
      10439 }
      +
      10415  VMA_VALIDATE(offset <= GetSize());
      +
      10416  VMA_VALIDATE(m_SumFreeSize == GetSize() - sumUsedSize);
      +
      10417 
      +
      10418  return true;
      +
      10419 }
      +
      10420 
      +
      10421 size_t VmaBlockMetadata_Linear::GetAllocationCount() const
      +
      10422 {
      +
      10423  return AccessSuballocations1st().size() - (m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount) +
      +
      10424  AccessSuballocations2nd().size() - m_2ndNullItemsCount;
      +
      10425 }
      +
      10426 
      +
      10427 VkDeviceSize VmaBlockMetadata_Linear::GetUnusedRangeSizeMax() const
      +
      10428 {
      +
      10429  const VkDeviceSize size = GetSize();
      +
      10430 
      +
      10431  /*
      +
      10432  We don't consider gaps inside allocation vectors with freed allocations because
      +
      10433  they are not suitable for reuse in linear allocator. We consider only space that
      +
      10434  is available for new allocations.
      +
      10435  */
      +
      10436  if(IsEmpty())
      +
      10437  {
      +
      10438  return size;
      +
      10439  }
      10440 
      -
      10441 void VmaBlockMetadata_Linear::AddPoolStats(VmaPoolStats& inoutStats) const
      -
      10442 {
      -
      10443  const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      -
      10444  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      -
      10445  const VkDeviceSize size = GetSize();
      -
      10446  const size_t suballoc1stCount = suballocations1st.size();
      -
      10447  const size_t suballoc2ndCount = suballocations2nd.size();
      -
      10448 
      -
      10449  inoutStats.size += size;
      -
      10450 
      -
      10451  VkDeviceSize lastOffset = 0;
      -
      10452 
      -
      10453  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
      -
      10454  {
      -
      10455  const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
      -
      10456  size_t nextAlloc2ndIndex = m_1stNullItemsBeginCount;
      -
      10457  while(lastOffset < freeSpace2ndTo1stEnd)
      -
      10458  {
      -
      10459  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
      -
      10460  while(nextAlloc2ndIndex < suballoc2ndCount &&
      -
      10461  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
      -
      10462  {
      -
      10463  ++nextAlloc2ndIndex;
      -
      10464  }
      -
      10465 
      -
      10466  // Found non-null allocation.
      -
      10467  if(nextAlloc2ndIndex < suballoc2ndCount)
      -
      10468  {
      -
      10469  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
      -
      10470 
      -
      10471  // 1. Process free space before this allocation.
      -
      10472  if(lastOffset < suballoc.offset)
      -
      10473  {
      -
      10474  // There is free space from lastOffset to suballoc.offset.
      -
      10475  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
      -
      10476  inoutStats.unusedSize += unusedRangeSize;
      -
      10477  ++inoutStats.unusedRangeCount;
      -
      10478  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
      -
      10479  }
      -
      10480 
      -
      10481  // 2. Process this allocation.
      -
      10482  // There is allocation with suballoc.offset, suballoc.size.
      -
      10483  ++inoutStats.allocationCount;
      +
      10441  const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      +
      10442 
      +
      10443  switch(m_2ndVectorMode)
      +
      10444  {
      +
      10445  case SECOND_VECTOR_EMPTY:
      +
      10446  /*
      +
      10447  Available space is after end of 1st, as well as before beginning of 1st (which
      +
      10448  whould make it a ring buffer).
      +
      10449  */
      +
      10450  {
      +
      10451  const size_t suballocations1stCount = suballocations1st.size();
      +
      10452  VMA_ASSERT(suballocations1stCount > m_1stNullItemsBeginCount);
      +
      10453  const VmaSuballocation& firstSuballoc = suballocations1st[m_1stNullItemsBeginCount];
      +
      10454  const VmaSuballocation& lastSuballoc = suballocations1st[suballocations1stCount - 1];
      +
      10455  return VMA_MAX(
      +
      10456  firstSuballoc.offset,
      +
      10457  size - (lastSuballoc.offset + lastSuballoc.size));
      +
      10458  }
      +
      10459  break;
      +
      10460 
      +
      10461  case SECOND_VECTOR_RING_BUFFER:
      +
      10462  /*
      +
      10463  Available space is only between end of 2nd and beginning of 1st.
      +
      10464  */
      +
      10465  {
      +
      10466  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      +
      10467  const VmaSuballocation& lastSuballoc2nd = suballocations2nd.back();
      +
      10468  const VmaSuballocation& firstSuballoc1st = suballocations1st[m_1stNullItemsBeginCount];
      +
      10469  return firstSuballoc1st.offset - (lastSuballoc2nd.offset + lastSuballoc2nd.size);
      +
      10470  }
      +
      10471  break;
      +
      10472 
      +
      10473  case SECOND_VECTOR_DOUBLE_STACK:
      +
      10474  /*
      +
      10475  Available space is only between end of 1st and top of 2nd.
      +
      10476  */
      +
      10477  {
      +
      10478  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      +
      10479  const VmaSuballocation& topSuballoc2nd = suballocations2nd.back();
      +
      10480  const VmaSuballocation& lastSuballoc1st = suballocations1st.back();
      +
      10481  return topSuballoc2nd.offset - (lastSuballoc1st.offset + lastSuballoc1st.size);
      +
      10482  }
      +
      10483  break;
      10484 
      -
      10485  // 3. Prepare for next iteration.
      -
      10486  lastOffset = suballoc.offset + suballoc.size;
      -
      10487  ++nextAlloc2ndIndex;
      -
      10488  }
      -
      10489  // We are at the end.
      -
      10490  else
      -
      10491  {
      -
      10492  if(lastOffset < freeSpace2ndTo1stEnd)
      -
      10493  {
      -
      10494  // There is free space from lastOffset to freeSpace2ndTo1stEnd.
      -
      10495  const VkDeviceSize unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset;
      -
      10496  inoutStats.unusedSize += unusedRangeSize;
      -
      10497  ++inoutStats.unusedRangeCount;
      -
      10498  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
      -
      10499  }
      -
      10500 
      -
      10501  // End of loop.
      -
      10502  lastOffset = freeSpace2ndTo1stEnd;
      -
      10503  }
      -
      10504  }
      -
      10505  }
      -
      10506 
      -
      10507  size_t nextAlloc1stIndex = m_1stNullItemsBeginCount;
      -
      10508  const VkDeviceSize freeSpace1stTo2ndEnd =
      -
      10509  m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size;
      -
      10510  while(lastOffset < freeSpace1stTo2ndEnd)
      +
      10485  default:
      +
      10486  VMA_ASSERT(0);
      +
      10487  return 0;
      +
      10488  }
      +
      10489 }
      +
      10490 
      +
      10491 void VmaBlockMetadata_Linear::CalcAllocationStatInfo(VmaStatInfo& outInfo) const
      +
      10492 {
      +
      10493  const VkDeviceSize size = GetSize();
      +
      10494  const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      +
      10495  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      +
      10496  const size_t suballoc1stCount = suballocations1st.size();
      +
      10497  const size_t suballoc2ndCount = suballocations2nd.size();
      +
      10498 
      +
      10499  outInfo.blockCount = 1;
      +
      10500  outInfo.allocationCount = (uint32_t)GetAllocationCount();
      +
      10501  outInfo.unusedRangeCount = 0;
      +
      10502  outInfo.usedBytes = 0;
      +
      10503  outInfo.allocationSizeMin = UINT64_MAX;
      +
      10504  outInfo.allocationSizeMax = 0;
      +
      10505  outInfo.unusedRangeSizeMin = UINT64_MAX;
      +
      10506  outInfo.unusedRangeSizeMax = 0;
      +
      10507 
      +
      10508  VkDeviceSize lastOffset = 0;
      +
      10509 
      +
      10510  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
      10511  {
      -
      10512  // Find next non-null allocation or move nextAllocIndex to the end.
      -
      10513  while(nextAlloc1stIndex < suballoc1stCount &&
      -
      10514  suballocations1st[nextAlloc1stIndex].hAllocation == VK_NULL_HANDLE)
      +
      10512  const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
      +
      10513  size_t nextAlloc2ndIndex = 0;
      +
      10514  while(lastOffset < freeSpace2ndTo1stEnd)
      10515  {
      -
      10516  ++nextAlloc1stIndex;
      -
      10517  }
      -
      10518 
      -
      10519  // Found non-null allocation.
      -
      10520  if(nextAlloc1stIndex < suballoc1stCount)
      -
      10521  {
      -
      10522  const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex];
      -
      10523 
      -
      10524  // 1. Process free space before this allocation.
      -
      10525  if(lastOffset < suballoc.offset)
      -
      10526  {
      -
      10527  // There is free space from lastOffset to suballoc.offset.
      -
      10528  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
      -
      10529  inoutStats.unusedSize += unusedRangeSize;
      -
      10530  ++inoutStats.unusedRangeCount;
      -
      10531  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
      -
      10532  }
      -
      10533 
      -
      10534  // 2. Process this allocation.
      -
      10535  // There is allocation with suballoc.offset, suballoc.size.
      -
      10536  ++inoutStats.allocationCount;
      -
      10537 
      -
      10538  // 3. Prepare for next iteration.
      -
      10539  lastOffset = suballoc.offset + suballoc.size;
      -
      10540  ++nextAlloc1stIndex;
      -
      10541  }
      -
      10542  // We are at the end.
      -
      10543  else
      -
      10544  {
      -
      10545  if(lastOffset < freeSpace1stTo2ndEnd)
      -
      10546  {
      -
      10547  // There is free space from lastOffset to freeSpace1stTo2ndEnd.
      -
      10548  const VkDeviceSize unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset;
      -
      10549  inoutStats.unusedSize += unusedRangeSize;
      -
      10550  ++inoutStats.unusedRangeCount;
      -
      10551  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
      -
      10552  }
      -
      10553 
      -
      10554  // End of loop.
      -
      10555  lastOffset = freeSpace1stTo2ndEnd;
      -
      10556  }
      -
      10557  }
      -
      10558 
      -
      10559  if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
      -
      10560  {
      -
      10561  size_t nextAlloc2ndIndex = suballocations2nd.size() - 1;
      -
      10562  while(lastOffset < size)
      -
      10563  {
      -
      10564  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
      -
      10565  while(nextAlloc2ndIndex != SIZE_MAX &&
      -
      10566  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
      -
      10567  {
      -
      10568  --nextAlloc2ndIndex;
      -
      10569  }
      -
      10570 
      -
      10571  // Found non-null allocation.
      -
      10572  if(nextAlloc2ndIndex != SIZE_MAX)
      -
      10573  {
      -
      10574  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
      -
      10575 
      -
      10576  // 1. Process free space before this allocation.
      -
      10577  if(lastOffset < suballoc.offset)
      -
      10578  {
      -
      10579  // There is free space from lastOffset to suballoc.offset.
      -
      10580  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
      -
      10581  inoutStats.unusedSize += unusedRangeSize;
      -
      10582  ++inoutStats.unusedRangeCount;
      -
      10583  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
      -
      10584  }
      -
      10585 
      -
      10586  // 2. Process this allocation.
      -
      10587  // There is allocation with suballoc.offset, suballoc.size.
      -
      10588  ++inoutStats.allocationCount;
      -
      10589 
      -
      10590  // 3. Prepare for next iteration.
      -
      10591  lastOffset = suballoc.offset + suballoc.size;
      -
      10592  --nextAlloc2ndIndex;
      -
      10593  }
      -
      10594  // We are at the end.
      -
      10595  else
      -
      10596  {
      -
      10597  if(lastOffset < size)
      -
      10598  {
      -
      10599  // There is free space from lastOffset to size.
      -
      10600  const VkDeviceSize unusedRangeSize = size - lastOffset;
      -
      10601  inoutStats.unusedSize += unusedRangeSize;
      -
      10602  ++inoutStats.unusedRangeCount;
      -
      10603  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
      -
      10604  }
      -
      10605 
      -
      10606  // End of loop.
      -
      10607  lastOffset = size;
      -
      10608  }
      -
      10609  }
      -
      10610  }
      -
      10611 }
      -
      10612 
      -
      10613 #if VMA_STATS_STRING_ENABLED
      -
      10614 void VmaBlockMetadata_Linear::PrintDetailedMap(class VmaJsonWriter& json) const
      -
      10615 {
      -
      10616  const VkDeviceSize size = GetSize();
      -
      10617  const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      -
      10618  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      -
      10619  const size_t suballoc1stCount = suballocations1st.size();
      -
      10620  const size_t suballoc2ndCount = suballocations2nd.size();
      -
      10621 
      -
      10622  // FIRST PASS
      +
      10516  // Find next non-null allocation or move nextAllocIndex to the end.
      +
      10517  while(nextAlloc2ndIndex < suballoc2ndCount &&
      +
      10518  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
      +
      10519  {
      +
      10520  ++nextAlloc2ndIndex;
      +
      10521  }
      +
      10522 
      +
      10523  // Found non-null allocation.
      +
      10524  if(nextAlloc2ndIndex < suballoc2ndCount)
      +
      10525  {
      +
      10526  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
      +
      10527 
      +
      10528  // 1. Process free space before this allocation.
      +
      10529  if(lastOffset < suballoc.offset)
      +
      10530  {
      +
      10531  // There is free space from lastOffset to suballoc.offset.
      +
      10532  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
      +
      10533  ++outInfo.unusedRangeCount;
      +
      10534  outInfo.unusedBytes += unusedRangeSize;
      +
      10535  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
      +
      10536  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
      +
      10537  }
      +
      10538 
      +
      10539  // 2. Process this allocation.
      +
      10540  // There is allocation with suballoc.offset, suballoc.size.
      +
      10541  outInfo.usedBytes += suballoc.size;
      +
      10542  outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size);
      +
      10543  outInfo.allocationSizeMax = VMA_MIN(outInfo.allocationSizeMax, suballoc.size);
      +
      10544 
      +
      10545  // 3. Prepare for next iteration.
      +
      10546  lastOffset = suballoc.offset + suballoc.size;
      +
      10547  ++nextAlloc2ndIndex;
      +
      10548  }
      +
      10549  // We are at the end.
      +
      10550  else
      +
      10551  {
      +
      10552  // There is free space from lastOffset to freeSpace2ndTo1stEnd.
      +
      10553  if(lastOffset < freeSpace2ndTo1stEnd)
      +
      10554  {
      +
      10555  const VkDeviceSize unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset;
      +
      10556  ++outInfo.unusedRangeCount;
      +
      10557  outInfo.unusedBytes += unusedRangeSize;
      +
      10558  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
      +
      10559  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
      +
      10560  }
      +
      10561 
      +
      10562  // End of loop.
      +
      10563  lastOffset = freeSpace2ndTo1stEnd;
      +
      10564  }
      +
      10565  }
      +
      10566  }
      +
      10567 
      +
      10568  size_t nextAlloc1stIndex = m_1stNullItemsBeginCount;
      +
      10569  const VkDeviceSize freeSpace1stTo2ndEnd =
      +
      10570  m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size;
      +
      10571  while(lastOffset < freeSpace1stTo2ndEnd)
      +
      10572  {
      +
      10573  // Find next non-null allocation or move nextAllocIndex to the end.
      +
      10574  while(nextAlloc1stIndex < suballoc1stCount &&
      +
      10575  suballocations1st[nextAlloc1stIndex].hAllocation == VK_NULL_HANDLE)
      +
      10576  {
      +
      10577  ++nextAlloc1stIndex;
      +
      10578  }
      +
      10579 
      +
      10580  // Found non-null allocation.
      +
      10581  if(nextAlloc1stIndex < suballoc1stCount)
      +
      10582  {
      +
      10583  const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex];
      +
      10584 
      +
      10585  // 1. Process free space before this allocation.
      +
      10586  if(lastOffset < suballoc.offset)
      +
      10587  {
      +
      10588  // There is free space from lastOffset to suballoc.offset.
      +
      10589  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
      +
      10590  ++outInfo.unusedRangeCount;
      +
      10591  outInfo.unusedBytes += unusedRangeSize;
      +
      10592  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
      +
      10593  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
      +
      10594  }
      +
      10595 
      +
      10596  // 2. Process this allocation.
      +
      10597  // There is allocation with suballoc.offset, suballoc.size.
      +
      10598  outInfo.usedBytes += suballoc.size;
      +
      10599  outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size);
      +
      10600  outInfo.allocationSizeMax = VMA_MIN(outInfo.allocationSizeMax, suballoc.size);
      +
      10601 
      +
      10602  // 3. Prepare for next iteration.
      +
      10603  lastOffset = suballoc.offset + suballoc.size;
      +
      10604  ++nextAlloc1stIndex;
      +
      10605  }
      +
      10606  // We are at the end.
      +
      10607  else
      +
      10608  {
      +
      10609  // There is free space from lastOffset to freeSpace1stTo2ndEnd.
      +
      10610  if(lastOffset < freeSpace1stTo2ndEnd)
      +
      10611  {
      +
      10612  const VkDeviceSize unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset;
      +
      10613  ++outInfo.unusedRangeCount;
      +
      10614  outInfo.unusedBytes += unusedRangeSize;
      +
      10615  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
      +
      10616  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
      +
      10617  }
      +
      10618 
      +
      10619  // End of loop.
      +
      10620  lastOffset = freeSpace1stTo2ndEnd;
      +
      10621  }
      +
      10622  }
      10623 
      -
      10624  size_t unusedRangeCount = 0;
      -
      10625  VkDeviceSize usedBytes = 0;
      -
      10626 
      -
      10627  VkDeviceSize lastOffset = 0;
      -
      10628 
      -
      10629  size_t alloc2ndCount = 0;
      -
      10630  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
      -
      10631  {
      -
      10632  const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
      -
      10633  size_t nextAlloc2ndIndex = 0;
      -
      10634  while(lastOffset < freeSpace2ndTo1stEnd)
      -
      10635  {
      -
      10636  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
      -
      10637  while(nextAlloc2ndIndex < suballoc2ndCount &&
      -
      10638  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
      -
      10639  {
      -
      10640  ++nextAlloc2ndIndex;
      -
      10641  }
      -
      10642 
      -
      10643  // Found non-null allocation.
      -
      10644  if(nextAlloc2ndIndex < suballoc2ndCount)
      -
      10645  {
      -
      10646  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
      -
      10647 
      -
      10648  // 1. Process free space before this allocation.
      -
      10649  if(lastOffset < suballoc.offset)
      -
      10650  {
      -
      10651  // There is free space from lastOffset to suballoc.offset.
      -
      10652  ++unusedRangeCount;
      -
      10653  }
      -
      10654 
      -
      10655  // 2. Process this allocation.
      -
      10656  // There is allocation with suballoc.offset, suballoc.size.
      -
      10657  ++alloc2ndCount;
      -
      10658  usedBytes += suballoc.size;
      -
      10659 
      -
      10660  // 3. Prepare for next iteration.
      -
      10661  lastOffset = suballoc.offset + suballoc.size;
      -
      10662  ++nextAlloc2ndIndex;
      -
      10663  }
      -
      10664  // We are at the end.
      -
      10665  else
      -
      10666  {
      -
      10667  if(lastOffset < freeSpace2ndTo1stEnd)
      -
      10668  {
      -
      10669  // There is free space from lastOffset to freeSpace2ndTo1stEnd.
      -
      10670  ++unusedRangeCount;
      -
      10671  }
      -
      10672 
      -
      10673  // End of loop.
      -
      10674  lastOffset = freeSpace2ndTo1stEnd;
      -
      10675  }
      -
      10676  }
      -
      10677  }
      -
      10678 
      -
      10679  size_t nextAlloc1stIndex = m_1stNullItemsBeginCount;
      -
      10680  size_t alloc1stCount = 0;
      -
      10681  const VkDeviceSize freeSpace1stTo2ndEnd =
      -
      10682  m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size;
      -
      10683  while(lastOffset < freeSpace1stTo2ndEnd)
      -
      10684  {
      -
      10685  // Find next non-null allocation or move nextAllocIndex to the end.
      -
      10686  while(nextAlloc1stIndex < suballoc1stCount &&
      -
      10687  suballocations1st[nextAlloc1stIndex].hAllocation == VK_NULL_HANDLE)
      -
      10688  {
      -
      10689  ++nextAlloc1stIndex;
      -
      10690  }
      +
      10624  if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
      +
      10625  {
      +
      10626  size_t nextAlloc2ndIndex = suballocations2nd.size() - 1;
      +
      10627  while(lastOffset < size)
      +
      10628  {
      +
      10629  // Find next non-null allocation or move nextAllocIndex to the end.
      +
      10630  while(nextAlloc2ndIndex != SIZE_MAX &&
      +
      10631  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
      +
      10632  {
      +
      10633  --nextAlloc2ndIndex;
      +
      10634  }
      +
      10635 
      +
      10636  // Found non-null allocation.
      +
      10637  if(nextAlloc2ndIndex != SIZE_MAX)
      +
      10638  {
      +
      10639  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
      +
      10640 
      +
      10641  // 1. Process free space before this allocation.
      +
      10642  if(lastOffset < suballoc.offset)
      +
      10643  {
      +
      10644  // There is free space from lastOffset to suballoc.offset.
      +
      10645  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
      +
      10646  ++outInfo.unusedRangeCount;
      +
      10647  outInfo.unusedBytes += unusedRangeSize;
      +
      10648  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
      +
      10649  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
      +
      10650  }
      +
      10651 
      +
      10652  // 2. Process this allocation.
      +
      10653  // There is allocation with suballoc.offset, suballoc.size.
      +
      10654  outInfo.usedBytes += suballoc.size;
      +
      10655  outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size);
      +
      10656  outInfo.allocationSizeMax = VMA_MIN(outInfo.allocationSizeMax, suballoc.size);
      +
      10657 
      +
      10658  // 3. Prepare for next iteration.
      +
      10659  lastOffset = suballoc.offset + suballoc.size;
      +
      10660  --nextAlloc2ndIndex;
      +
      10661  }
      +
      10662  // We are at the end.
      +
      10663  else
      +
      10664  {
      +
      10665  // There is free space from lastOffset to size.
      +
      10666  if(lastOffset < size)
      +
      10667  {
      +
      10668  const VkDeviceSize unusedRangeSize = size - lastOffset;
      +
      10669  ++outInfo.unusedRangeCount;
      +
      10670  outInfo.unusedBytes += unusedRangeSize;
      +
      10671  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);
      +
      10672  outInfo.unusedRangeSizeMax = VMA_MIN(outInfo.unusedRangeSizeMax, unusedRangeSize);
      +
      10673  }
      +
      10674 
      +
      10675  // End of loop.
      +
      10676  lastOffset = size;
      +
      10677  }
      +
      10678  }
      +
      10679  }
      +
      10680 
      +
      10681  outInfo.unusedBytes = size - outInfo.usedBytes;
      +
      10682 }
      +
      10683 
      +
      10684 void VmaBlockMetadata_Linear::AddPoolStats(VmaPoolStats& inoutStats) const
      +
      10685 {
      +
      10686  const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      +
      10687  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      +
      10688  const VkDeviceSize size = GetSize();
      +
      10689  const size_t suballoc1stCount = suballocations1st.size();
      +
      10690  const size_t suballoc2ndCount = suballocations2nd.size();
      10691 
      -
      10692  // Found non-null allocation.
      -
      10693  if(nextAlloc1stIndex < suballoc1stCount)
      -
      10694  {
      -
      10695  const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex];
      -
      10696 
      -
      10697  // 1. Process free space before this allocation.
      -
      10698  if(lastOffset < suballoc.offset)
      -
      10699  {
      -
      10700  // There is free space from lastOffset to suballoc.offset.
      -
      10701  ++unusedRangeCount;
      -
      10702  }
      -
      10703 
      -
      10704  // 2. Process this allocation.
      -
      10705  // There is allocation with suballoc.offset, suballoc.size.
      -
      10706  ++alloc1stCount;
      -
      10707  usedBytes += suballoc.size;
      +
      10692  inoutStats.size += size;
      +
      10693 
      +
      10694  VkDeviceSize lastOffset = 0;
      +
      10695 
      +
      10696  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
      +
      10697  {
      +
      10698  const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
      +
      10699  size_t nextAlloc2ndIndex = m_1stNullItemsBeginCount;
      +
      10700  while(lastOffset < freeSpace2ndTo1stEnd)
      +
      10701  {
      +
      10702  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
      +
      10703  while(nextAlloc2ndIndex < suballoc2ndCount &&
      +
      10704  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
      +
      10705  {
      +
      10706  ++nextAlloc2ndIndex;
      +
      10707  }
      10708 
      -
      10709  // 3. Prepare for next iteration.
      -
      10710  lastOffset = suballoc.offset + suballoc.size;
      -
      10711  ++nextAlloc1stIndex;
      -
      10712  }
      -
      10713  // We are at the end.
      -
      10714  else
      -
      10715  {
      -
      10716  if(lastOffset < size)
      -
      10717  {
      -
      10718  // There is free space from lastOffset to freeSpace1stTo2ndEnd.
      -
      10719  ++unusedRangeCount;
      -
      10720  }
      -
      10721 
      -
      10722  // End of loop.
      -
      10723  lastOffset = freeSpace1stTo2ndEnd;
      -
      10724  }
      -
      10725  }
      -
      10726 
      -
      10727  if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
      -
      10728  {
      -
      10729  size_t nextAlloc2ndIndex = suballocations2nd.size() - 1;
      -
      10730  while(lastOffset < size)
      -
      10731  {
      -
      10732  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
      -
      10733  while(nextAlloc2ndIndex != SIZE_MAX &&
      -
      10734  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
      -
      10735  {
      -
      10736  --nextAlloc2ndIndex;
      -
      10737  }
      -
      10738 
      -
      10739  // Found non-null allocation.
      -
      10740  if(nextAlloc2ndIndex != SIZE_MAX)
      -
      10741  {
      -
      10742  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
      +
      10709  // Found non-null allocation.
      +
      10710  if(nextAlloc2ndIndex < suballoc2ndCount)
      +
      10711  {
      +
      10712  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
      +
      10713 
      +
      10714  // 1. Process free space before this allocation.
      +
      10715  if(lastOffset < suballoc.offset)
      +
      10716  {
      +
      10717  // There is free space from lastOffset to suballoc.offset.
      +
      10718  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
      +
      10719  inoutStats.unusedSize += unusedRangeSize;
      +
      10720  ++inoutStats.unusedRangeCount;
      +
      10721  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
      +
      10722  }
      +
      10723 
      +
      10724  // 2. Process this allocation.
      +
      10725  // There is allocation with suballoc.offset, suballoc.size.
      +
      10726  ++inoutStats.allocationCount;
      +
      10727 
      +
      10728  // 3. Prepare for next iteration.
      +
      10729  lastOffset = suballoc.offset + suballoc.size;
      +
      10730  ++nextAlloc2ndIndex;
      +
      10731  }
      +
      10732  // We are at the end.
      +
      10733  else
      +
      10734  {
      +
      10735  if(lastOffset < freeSpace2ndTo1stEnd)
      +
      10736  {
      +
      10737  // There is free space from lastOffset to freeSpace2ndTo1stEnd.
      +
      10738  const VkDeviceSize unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset;
      +
      10739  inoutStats.unusedSize += unusedRangeSize;
      +
      10740  ++inoutStats.unusedRangeCount;
      +
      10741  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
      +
      10742  }
      10743 
      -
      10744  // 1. Process free space before this allocation.
      -
      10745  if(lastOffset < suballoc.offset)
      -
      10746  {
      -
      10747  // There is free space from lastOffset to suballoc.offset.
      -
      10748  ++unusedRangeCount;
      -
      10749  }
      -
      10750 
      -
      10751  // 2. Process this allocation.
      -
      10752  // There is allocation with suballoc.offset, suballoc.size.
      -
      10753  ++alloc2ndCount;
      -
      10754  usedBytes += suballoc.size;
      -
      10755 
      -
      10756  // 3. Prepare for next iteration.
      -
      10757  lastOffset = suballoc.offset + suballoc.size;
      -
      10758  --nextAlloc2ndIndex;
      -
      10759  }
      -
      10760  // We are at the end.
      -
      10761  else
      -
      10762  {
      -
      10763  if(lastOffset < size)
      -
      10764  {
      -
      10765  // There is free space from lastOffset to size.
      -
      10766  ++unusedRangeCount;
      -
      10767  }
      -
      10768 
      -
      10769  // End of loop.
      -
      10770  lastOffset = size;
      -
      10771  }
      -
      10772  }
      -
      10773  }
      -
      10774 
      -
      10775  const VkDeviceSize unusedBytes = size - usedBytes;
      -
      10776  PrintDetailedMap_Begin(json, unusedBytes, alloc1stCount + alloc2ndCount, unusedRangeCount);
      -
      10777 
      -
      10778  // SECOND PASS
      -
      10779  lastOffset = 0;
      +
      10744  // End of loop.
      +
      10745  lastOffset = freeSpace2ndTo1stEnd;
      +
      10746  }
      +
      10747  }
      +
      10748  }
      +
      10749 
      +
      10750  size_t nextAlloc1stIndex = m_1stNullItemsBeginCount;
      +
      10751  const VkDeviceSize freeSpace1stTo2ndEnd =
      +
      10752  m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size;
      +
      10753  while(lastOffset < freeSpace1stTo2ndEnd)
      +
      10754  {
      +
      10755  // Find next non-null allocation or move nextAllocIndex to the end.
      +
      10756  while(nextAlloc1stIndex < suballoc1stCount &&
      +
      10757  suballocations1st[nextAlloc1stIndex].hAllocation == VK_NULL_HANDLE)
      +
      10758  {
      +
      10759  ++nextAlloc1stIndex;
      +
      10760  }
      +
      10761 
      +
      10762  // Found non-null allocation.
      +
      10763  if(nextAlloc1stIndex < suballoc1stCount)
      +
      10764  {
      +
      10765  const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex];
      +
      10766 
      +
      10767  // 1. Process free space before this allocation.
      +
      10768  if(lastOffset < suballoc.offset)
      +
      10769  {
      +
      10770  // There is free space from lastOffset to suballoc.offset.
      +
      10771  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
      +
      10772  inoutStats.unusedSize += unusedRangeSize;
      +
      10773  ++inoutStats.unusedRangeCount;
      +
      10774  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
      +
      10775  }
      +
      10776 
      +
      10777  // 2. Process this allocation.
      +
      10778  // There is allocation with suballoc.offset, suballoc.size.
      +
      10779  ++inoutStats.allocationCount;
      10780 
      -
      10781  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
      -
      10782  {
      -
      10783  const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
      -
      10784  size_t nextAlloc2ndIndex = 0;
      -
      10785  while(lastOffset < freeSpace2ndTo1stEnd)
      -
      10786  {
      -
      10787  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
      -
      10788  while(nextAlloc2ndIndex < suballoc2ndCount &&
      -
      10789  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
      -
      10790  {
      -
      10791  ++nextAlloc2ndIndex;
      -
      10792  }
      -
      10793 
      -
      10794  // Found non-null allocation.
      -
      10795  if(nextAlloc2ndIndex < suballoc2ndCount)
      -
      10796  {
      -
      10797  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
      -
      10798 
      -
      10799  // 1. Process free space before this allocation.
      -
      10800  if(lastOffset < suballoc.offset)
      -
      10801  {
      -
      10802  // There is free space from lastOffset to suballoc.offset.
      -
      10803  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
      -
      10804  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
      -
      10805  }
      -
      10806 
      -
      10807  // 2. Process this allocation.
      -
      10808  // There is allocation with suballoc.offset, suballoc.size.
      -
      10809  PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.hAllocation);
      -
      10810 
      -
      10811  // 3. Prepare for next iteration.
      -
      10812  lastOffset = suballoc.offset + suballoc.size;
      -
      10813  ++nextAlloc2ndIndex;
      -
      10814  }
      -
      10815  // We are at the end.
      -
      10816  else
      -
      10817  {
      -
      10818  if(lastOffset < freeSpace2ndTo1stEnd)
      -
      10819  {
      -
      10820  // There is free space from lastOffset to freeSpace2ndTo1stEnd.
      -
      10821  const VkDeviceSize unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset;
      -
      10822  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
      -
      10823  }
      -
      10824 
      -
      10825  // End of loop.
      -
      10826  lastOffset = freeSpace2ndTo1stEnd;
      -
      10827  }
      -
      10828  }
      -
      10829  }
      -
      10830 
      -
      10831  nextAlloc1stIndex = m_1stNullItemsBeginCount;
      -
      10832  while(lastOffset < freeSpace1stTo2ndEnd)
      -
      10833  {
      -
      10834  // Find next non-null allocation or move nextAllocIndex to the end.
      -
      10835  while(nextAlloc1stIndex < suballoc1stCount &&
      -
      10836  suballocations1st[nextAlloc1stIndex].hAllocation == VK_NULL_HANDLE)
      -
      10837  {
      -
      10838  ++nextAlloc1stIndex;
      -
      10839  }
      -
      10840 
      -
      10841  // Found non-null allocation.
      -
      10842  if(nextAlloc1stIndex < suballoc1stCount)
      -
      10843  {
      -
      10844  const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex];
      -
      10845 
      -
      10846  // 1. Process free space before this allocation.
      -
      10847  if(lastOffset < suballoc.offset)
      -
      10848  {
      -
      10849  // There is free space from lastOffset to suballoc.offset.
      -
      10850  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
      -
      10851  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
      -
      10852  }
      -
      10853 
      -
      10854  // 2. Process this allocation.
      -
      10855  // There is allocation with suballoc.offset, suballoc.size.
      -
      10856  PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.hAllocation);
      -
      10857 
      -
      10858  // 3. Prepare for next iteration.
      -
      10859  lastOffset = suballoc.offset + suballoc.size;
      -
      10860  ++nextAlloc1stIndex;
      -
      10861  }
      -
      10862  // We are at the end.
      -
      10863  else
      -
      10864  {
      -
      10865  if(lastOffset < freeSpace1stTo2ndEnd)
      -
      10866  {
      -
      10867  // There is free space from lastOffset to freeSpace1stTo2ndEnd.
      -
      10868  const VkDeviceSize unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset;
      -
      10869  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
      -
      10870  }
      +
      10781  // 3. Prepare for next iteration.
      +
      10782  lastOffset = suballoc.offset + suballoc.size;
      +
      10783  ++nextAlloc1stIndex;
      +
      10784  }
      +
      10785  // We are at the end.
      +
      10786  else
      +
      10787  {
      +
      10788  if(lastOffset < freeSpace1stTo2ndEnd)
      +
      10789  {
      +
      10790  // There is free space from lastOffset to freeSpace1stTo2ndEnd.
      +
      10791  const VkDeviceSize unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset;
      +
      10792  inoutStats.unusedSize += unusedRangeSize;
      +
      10793  ++inoutStats.unusedRangeCount;
      +
      10794  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
      +
      10795  }
      +
      10796 
      +
      10797  // End of loop.
      +
      10798  lastOffset = freeSpace1stTo2ndEnd;
      +
      10799  }
      +
      10800  }
      +
      10801 
      +
      10802  if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
      +
      10803  {
      +
      10804  size_t nextAlloc2ndIndex = suballocations2nd.size() - 1;
      +
      10805  while(lastOffset < size)
      +
      10806  {
      +
      10807  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
      +
      10808  while(nextAlloc2ndIndex != SIZE_MAX &&
      +
      10809  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
      +
      10810  {
      +
      10811  --nextAlloc2ndIndex;
      +
      10812  }
      +
      10813 
      +
      10814  // Found non-null allocation.
      +
      10815  if(nextAlloc2ndIndex != SIZE_MAX)
      +
      10816  {
      +
      10817  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
      +
      10818 
      +
      10819  // 1. Process free space before this allocation.
      +
      10820  if(lastOffset < suballoc.offset)
      +
      10821  {
      +
      10822  // There is free space from lastOffset to suballoc.offset.
      +
      10823  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
      +
      10824  inoutStats.unusedSize += unusedRangeSize;
      +
      10825  ++inoutStats.unusedRangeCount;
      +
      10826  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
      +
      10827  }
      +
      10828 
      +
      10829  // 2. Process this allocation.
      +
      10830  // There is allocation with suballoc.offset, suballoc.size.
      +
      10831  ++inoutStats.allocationCount;
      +
      10832 
      +
      10833  // 3. Prepare for next iteration.
      +
      10834  lastOffset = suballoc.offset + suballoc.size;
      +
      10835  --nextAlloc2ndIndex;
      +
      10836  }
      +
      10837  // We are at the end.
      +
      10838  else
      +
      10839  {
      +
      10840  if(lastOffset < size)
      +
      10841  {
      +
      10842  // There is free space from lastOffset to size.
      +
      10843  const VkDeviceSize unusedRangeSize = size - lastOffset;
      +
      10844  inoutStats.unusedSize += unusedRangeSize;
      +
      10845  ++inoutStats.unusedRangeCount;
      +
      10846  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, unusedRangeSize);
      +
      10847  }
      +
      10848 
      +
      10849  // End of loop.
      +
      10850  lastOffset = size;
      +
      10851  }
      +
      10852  }
      +
      10853  }
      +
      10854 }
      +
      10855 
      +
      10856 #if VMA_STATS_STRING_ENABLED
      +
      10857 void VmaBlockMetadata_Linear::PrintDetailedMap(class VmaJsonWriter& json) const
      +
      10858 {
      +
      10859  const VkDeviceSize size = GetSize();
      +
      10860  const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      +
      10861  const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      +
      10862  const size_t suballoc1stCount = suballocations1st.size();
      +
      10863  const size_t suballoc2ndCount = suballocations2nd.size();
      +
      10864 
      +
      10865  // FIRST PASS
      +
      10866 
      +
      10867  size_t unusedRangeCount = 0;
      +
      10868  VkDeviceSize usedBytes = 0;
      +
      10869 
      +
      10870  VkDeviceSize lastOffset = 0;
      10871 
      -
      10872  // End of loop.
      -
      10873  lastOffset = freeSpace1stTo2ndEnd;
      -
      10874  }
      -
      10875  }
      -
      10876 
      -
      10877  if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
      -
      10878  {
      -
      10879  size_t nextAlloc2ndIndex = suballocations2nd.size() - 1;
      -
      10880  while(lastOffset < size)
      -
      10881  {
      -
      10882  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
      -
      10883  while(nextAlloc2ndIndex != SIZE_MAX &&
      -
      10884  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
      -
      10885  {
      -
      10886  --nextAlloc2ndIndex;
      -
      10887  }
      -
      10888 
      -
      10889  // Found non-null allocation.
      -
      10890  if(nextAlloc2ndIndex != SIZE_MAX)
      -
      10891  {
      -
      10892  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
      -
      10893 
      -
      10894  // 1. Process free space before this allocation.
      -
      10895  if(lastOffset < suballoc.offset)
      -
      10896  {
      -
      10897  // There is free space from lastOffset to suballoc.offset.
      -
      10898  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
      -
      10899  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
      -
      10900  }
      -
      10901 
      -
      10902  // 2. Process this allocation.
      -
      10903  // There is allocation with suballoc.offset, suballoc.size.
      -
      10904  PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.hAllocation);
      -
      10905 
      -
      10906  // 3. Prepare for next iteration.
      -
      10907  lastOffset = suballoc.offset + suballoc.size;
      -
      10908  --nextAlloc2ndIndex;
      -
      10909  }
      -
      10910  // We are at the end.
      -
      10911  else
      -
      10912  {
      -
      10913  if(lastOffset < size)
      -
      10914  {
      -
      10915  // There is free space from lastOffset to size.
      -
      10916  const VkDeviceSize unusedRangeSize = size - lastOffset;
      -
      10917  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
      -
      10918  }
      -
      10919 
      -
      10920  // End of loop.
      -
      10921  lastOffset = size;
      -
      10922  }
      -
      10923  }
      -
      10924  }
      -
      10925 
      -
      10926  PrintDetailedMap_End(json);
      -
      10927 }
      -
      10928 #endif // #if VMA_STATS_STRING_ENABLED
      -
      10929 
      -
      10930 bool VmaBlockMetadata_Linear::CreateAllocationRequest(
      -
      10931  uint32_t currentFrameIndex,
      -
      10932  uint32_t frameInUseCount,
      -
      10933  VkDeviceSize bufferImageGranularity,
      -
      10934  VkDeviceSize allocSize,
      -
      10935  VkDeviceSize allocAlignment,
      -
      10936  bool upperAddress,
      -
      10937  VmaSuballocationType allocType,
      -
      10938  bool canMakeOtherLost,
      -
      10939  uint32_t strategy,
      -
      10940  VmaAllocationRequest* pAllocationRequest)
      -
      10941 {
      -
      10942  VMA_ASSERT(allocSize > 0);
      -
      10943  VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE);
      -
      10944  VMA_ASSERT(pAllocationRequest != VMA_NULL);
      -
      10945  VMA_HEAVY_ASSERT(Validate());
      -
      10946  return upperAddress ?
      -
      10947  CreateAllocationRequest_UpperAddress(
      -
      10948  currentFrameIndex, frameInUseCount, bufferImageGranularity,
      -
      10949  allocSize, allocAlignment, allocType, canMakeOtherLost, strategy, pAllocationRequest) :
      -
      10950  CreateAllocationRequest_LowerAddress(
      -
      10951  currentFrameIndex, frameInUseCount, bufferImageGranularity,
      -
      10952  allocSize, allocAlignment, allocType, canMakeOtherLost, strategy, pAllocationRequest);
      -
      10953 }
      -
      10954 
      -
      10955 bool VmaBlockMetadata_Linear::CreateAllocationRequest_UpperAddress(
      -
      10956  uint32_t currentFrameIndex,
      -
      10957  uint32_t frameInUseCount,
      -
      10958  VkDeviceSize bufferImageGranularity,
      -
      10959  VkDeviceSize allocSize,
      -
      10960  VkDeviceSize allocAlignment,
      -
      10961  VmaSuballocationType allocType,
      -
      10962  bool canMakeOtherLost,
      -
      10963  uint32_t strategy,
      -
      10964  VmaAllocationRequest* pAllocationRequest)
      -
      10965 {
      -
      10966  const VkDeviceSize size = GetSize();
      -
      10967  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      -
      10968  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      +
      10872  size_t alloc2ndCount = 0;
      +
      10873  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
      +
      10874  {
      +
      10875  const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
      +
      10876  size_t nextAlloc2ndIndex = 0;
      +
      10877  while(lastOffset < freeSpace2ndTo1stEnd)
      +
      10878  {
      +
      10879  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
      +
      10880  while(nextAlloc2ndIndex < suballoc2ndCount &&
      +
      10881  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
      +
      10882  {
      +
      10883  ++nextAlloc2ndIndex;
      +
      10884  }
      +
      10885 
      +
      10886  // Found non-null allocation.
      +
      10887  if(nextAlloc2ndIndex < suballoc2ndCount)
      +
      10888  {
      +
      10889  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
      +
      10890 
      +
      10891  // 1. Process free space before this allocation.
      +
      10892  if(lastOffset < suballoc.offset)
      +
      10893  {
      +
      10894  // There is free space from lastOffset to suballoc.offset.
      +
      10895  ++unusedRangeCount;
      +
      10896  }
      +
      10897 
      +
      10898  // 2. Process this allocation.
      +
      10899  // There is allocation with suballoc.offset, suballoc.size.
      +
      10900  ++alloc2ndCount;
      +
      10901  usedBytes += suballoc.size;
      +
      10902 
      +
      10903  // 3. Prepare for next iteration.
      +
      10904  lastOffset = suballoc.offset + suballoc.size;
      +
      10905  ++nextAlloc2ndIndex;
      +
      10906  }
      +
      10907  // We are at the end.
      +
      10908  else
      +
      10909  {
      +
      10910  if(lastOffset < freeSpace2ndTo1stEnd)
      +
      10911  {
      +
      10912  // There is free space from lastOffset to freeSpace2ndTo1stEnd.
      +
      10913  ++unusedRangeCount;
      +
      10914  }
      +
      10915 
      +
      10916  // End of loop.
      +
      10917  lastOffset = freeSpace2ndTo1stEnd;
      +
      10918  }
      +
      10919  }
      +
      10920  }
      +
      10921 
      +
      10922  size_t nextAlloc1stIndex = m_1stNullItemsBeginCount;
      +
      10923  size_t alloc1stCount = 0;
      +
      10924  const VkDeviceSize freeSpace1stTo2ndEnd =
      +
      10925  m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size;
      +
      10926  while(lastOffset < freeSpace1stTo2ndEnd)
      +
      10927  {
      +
      10928  // Find next non-null allocation or move nextAllocIndex to the end.
      +
      10929  while(nextAlloc1stIndex < suballoc1stCount &&
      +
      10930  suballocations1st[nextAlloc1stIndex].hAllocation == VK_NULL_HANDLE)
      +
      10931  {
      +
      10932  ++nextAlloc1stIndex;
      +
      10933  }
      +
      10934 
      +
      10935  // Found non-null allocation.
      +
      10936  if(nextAlloc1stIndex < suballoc1stCount)
      +
      10937  {
      +
      10938  const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex];
      +
      10939 
      +
      10940  // 1. Process free space before this allocation.
      +
      10941  if(lastOffset < suballoc.offset)
      +
      10942  {
      +
      10943  // There is free space from lastOffset to suballoc.offset.
      +
      10944  ++unusedRangeCount;
      +
      10945  }
      +
      10946 
      +
      10947  // 2. Process this allocation.
      +
      10948  // There is allocation with suballoc.offset, suballoc.size.
      +
      10949  ++alloc1stCount;
      +
      10950  usedBytes += suballoc.size;
      +
      10951 
      +
      10952  // 3. Prepare for next iteration.
      +
      10953  lastOffset = suballoc.offset + suballoc.size;
      +
      10954  ++nextAlloc1stIndex;
      +
      10955  }
      +
      10956  // We are at the end.
      +
      10957  else
      +
      10958  {
      +
      10959  if(lastOffset < size)
      +
      10960  {
      +
      10961  // There is free space from lastOffset to freeSpace1stTo2ndEnd.
      +
      10962  ++unusedRangeCount;
      +
      10963  }
      +
      10964 
      +
      10965  // End of loop.
      +
      10966  lastOffset = freeSpace1stTo2ndEnd;
      +
      10967  }
      +
      10968  }
      10969 
      -
      10970  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
      +
      10970  if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
      10971  {
      -
      10972  VMA_ASSERT(0 && "Trying to use pool with linear algorithm as double stack, while it is already being used as ring buffer.");
      -
      10973  return false;
      -
      10974  }
      -
      10975 
      -
      10976  // Try to allocate before 2nd.back(), or end of block if 2nd.empty().
      -
      10977  if(allocSize > size)
      -
      10978  {
      -
      10979  return false;
      -
      10980  }
      -
      10981  VkDeviceSize resultBaseOffset = size - allocSize;
      -
      10982  if(!suballocations2nd.empty())
      -
      10983  {
      -
      10984  const VmaSuballocation& lastSuballoc = suballocations2nd.back();
      -
      10985  resultBaseOffset = lastSuballoc.offset - allocSize;
      -
      10986  if(allocSize > lastSuballoc.offset)
      -
      10987  {
      -
      10988  return false;
      -
      10989  }
      -
      10990  }
      -
      10991 
      -
      10992  // Start from offset equal to end of free space.
      -
      10993  VkDeviceSize resultOffset = resultBaseOffset;
      -
      10994 
      -
      10995  // Apply VMA_DEBUG_MARGIN at the end.
      -
      10996  if(VMA_DEBUG_MARGIN > 0)
      -
      10997  {
      -
      10998  if(resultOffset < VMA_DEBUG_MARGIN)
      -
      10999  {
      -
      11000  return false;
      -
      11001  }
      -
      11002  resultOffset -= VMA_DEBUG_MARGIN;
      -
      11003  }
      -
      11004 
      -
      11005  // Apply alignment.
      -
      11006  resultOffset = VmaAlignDown(resultOffset, allocAlignment);
      -
      11007 
      -
      11008  // Check next suballocations from 2nd for BufferImageGranularity conflicts.
      -
      11009  // Make bigger alignment if necessary.
      -
      11010  if(bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment && !suballocations2nd.empty())
      -
      11011  {
      -
      11012  bool bufferImageGranularityConflict = false;
      -
      11013  for(size_t nextSuballocIndex = suballocations2nd.size(); nextSuballocIndex--; )
      -
      11014  {
      -
      11015  const VmaSuballocation& nextSuballoc = suballocations2nd[nextSuballocIndex];
      -
      11016  if(VmaBlocksOnSamePage(resultOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
      -
      11017  {
      -
      11018  if(VmaIsBufferImageGranularityConflict(nextSuballoc.type, allocType))
      -
      11019  {
      -
      11020  bufferImageGranularityConflict = true;
      -
      11021  break;
      -
      11022  }
      -
      11023  }
      -
      11024  else
      -
      11025  // Already on previous page.
      -
      11026  break;
      -
      11027  }
      -
      11028  if(bufferImageGranularityConflict)
      +
      10972  size_t nextAlloc2ndIndex = suballocations2nd.size() - 1;
      +
      10973  while(lastOffset < size)
      +
      10974  {
      +
      10975  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
      +
      10976  while(nextAlloc2ndIndex != SIZE_MAX &&
      +
      10977  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
      +
      10978  {
      +
      10979  --nextAlloc2ndIndex;
      +
      10980  }
      +
      10981 
      +
      10982  // Found non-null allocation.
      +
      10983  if(nextAlloc2ndIndex != SIZE_MAX)
      +
      10984  {
      +
      10985  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
      +
      10986 
      +
      10987  // 1. Process free space before this allocation.
      +
      10988  if(lastOffset < suballoc.offset)
      +
      10989  {
      +
      10990  // There is free space from lastOffset to suballoc.offset.
      +
      10991  ++unusedRangeCount;
      +
      10992  }
      +
      10993 
      +
      10994  // 2. Process this allocation.
      +
      10995  // There is allocation with suballoc.offset, suballoc.size.
      +
      10996  ++alloc2ndCount;
      +
      10997  usedBytes += suballoc.size;
      +
      10998 
      +
      10999  // 3. Prepare for next iteration.
      +
      11000  lastOffset = suballoc.offset + suballoc.size;
      +
      11001  --nextAlloc2ndIndex;
      +
      11002  }
      +
      11003  // We are at the end.
      +
      11004  else
      +
      11005  {
      +
      11006  if(lastOffset < size)
      +
      11007  {
      +
      11008  // There is free space from lastOffset to size.
      +
      11009  ++unusedRangeCount;
      +
      11010  }
      +
      11011 
      +
      11012  // End of loop.
      +
      11013  lastOffset = size;
      +
      11014  }
      +
      11015  }
      +
      11016  }
      +
      11017 
      +
      11018  const VkDeviceSize unusedBytes = size - usedBytes;
      +
      11019  PrintDetailedMap_Begin(json, unusedBytes, alloc1stCount + alloc2ndCount, unusedRangeCount);
      +
      11020 
      +
      11021  // SECOND PASS
      +
      11022  lastOffset = 0;
      +
      11023 
      +
      11024  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
      +
      11025  {
      +
      11026  const VkDeviceSize freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
      +
      11027  size_t nextAlloc2ndIndex = 0;
      +
      11028  while(lastOffset < freeSpace2ndTo1stEnd)
      11029  {
      -
      11030  resultOffset = VmaAlignDown(resultOffset, bufferImageGranularity);
      -
      11031  }
      -
      11032  }
      -
      11033 
      -
      11034  // There is enough free space.
      -
      11035  const VkDeviceSize endOf1st = !suballocations1st.empty() ?
      -
      11036  suballocations1st.back().offset + suballocations1st.back().size :
      -
      11037  0;
      -
      11038  if(endOf1st + VMA_DEBUG_MARGIN <= resultOffset)
      -
      11039  {
      -
      11040  // Check previous suballocations for BufferImageGranularity conflicts.
      -
      11041  // If conflict exists, allocation cannot be made here.
      -
      11042  if(bufferImageGranularity > 1)
      -
      11043  {
      -
      11044  for(size_t prevSuballocIndex = suballocations1st.size(); prevSuballocIndex--; )
      -
      11045  {
      -
      11046  const VmaSuballocation& prevSuballoc = suballocations1st[prevSuballocIndex];
      -
      11047  if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, resultOffset, bufferImageGranularity))
      -
      11048  {
      -
      11049  if(VmaIsBufferImageGranularityConflict(allocType, prevSuballoc.type))
      -
      11050  {
      -
      11051  return false;
      -
      11052  }
      -
      11053  }
      -
      11054  else
      -
      11055  {
      -
      11056  // Already on next page.
      -
      11057  break;
      -
      11058  }
      -
      11059  }
      -
      11060  }
      -
      11061 
      -
      11062  // All tests passed: Success.
      -
      11063  pAllocationRequest->offset = resultOffset;
      -
      11064  pAllocationRequest->sumFreeSize = resultBaseOffset + allocSize - endOf1st;
      -
      11065  pAllocationRequest->sumItemSize = 0;
      -
      11066  // pAllocationRequest->item unused.
      -
      11067  pAllocationRequest->itemsToMakeLostCount = 0;
      -
      11068  pAllocationRequest->type = VmaAllocationRequestType::UpperAddress;
      -
      11069  return true;
      -
      11070  }
      -
      11071 
      -
      11072  return false;
      -
      11073 }
      -
      11074 
      -
      11075 bool VmaBlockMetadata_Linear::CreateAllocationRequest_LowerAddress(
      -
      11076  uint32_t currentFrameIndex,
      -
      11077  uint32_t frameInUseCount,
      -
      11078  VkDeviceSize bufferImageGranularity,
      -
      11079  VkDeviceSize allocSize,
      -
      11080  VkDeviceSize allocAlignment,
      -
      11081  VmaSuballocationType allocType,
      -
      11082  bool canMakeOtherLost,
      -
      11083  uint32_t strategy,
      -
      11084  VmaAllocationRequest* pAllocationRequest)
      -
      11085 {
      -
      11086  const VkDeviceSize size = GetSize();
      -
      11087  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      -
      11088  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      -
      11089 
      -
      11090  if(m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
      -
      11091  {
      -
      11092  // Try to allocate at the end of 1st vector.
      -
      11093 
      -
      11094  VkDeviceSize resultBaseOffset = 0;
      -
      11095  if(!suballocations1st.empty())
      -
      11096  {
      -
      11097  const VmaSuballocation& lastSuballoc = suballocations1st.back();
      -
      11098  resultBaseOffset = lastSuballoc.offset + lastSuballoc.size;
      -
      11099  }
      +
      11030  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
      +
      11031  while(nextAlloc2ndIndex < suballoc2ndCount &&
      +
      11032  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
      +
      11033  {
      +
      11034  ++nextAlloc2ndIndex;
      +
      11035  }
      +
      11036 
      +
      11037  // Found non-null allocation.
      +
      11038  if(nextAlloc2ndIndex < suballoc2ndCount)
      +
      11039  {
      +
      11040  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
      +
      11041 
      +
      11042  // 1. Process free space before this allocation.
      +
      11043  if(lastOffset < suballoc.offset)
      +
      11044  {
      +
      11045  // There is free space from lastOffset to suballoc.offset.
      +
      11046  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
      +
      11047  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
      +
      11048  }
      +
      11049 
      +
      11050  // 2. Process this allocation.
      +
      11051  // There is allocation with suballoc.offset, suballoc.size.
      +
      11052  PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.hAllocation);
      +
      11053 
      +
      11054  // 3. Prepare for next iteration.
      +
      11055  lastOffset = suballoc.offset + suballoc.size;
      +
      11056  ++nextAlloc2ndIndex;
      +
      11057  }
      +
      11058  // We are at the end.
      +
      11059  else
      +
      11060  {
      +
      11061  if(lastOffset < freeSpace2ndTo1stEnd)
      +
      11062  {
      +
      11063  // There is free space from lastOffset to freeSpace2ndTo1stEnd.
      +
      11064  const VkDeviceSize unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset;
      +
      11065  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
      +
      11066  }
      +
      11067 
      +
      11068  // End of loop.
      +
      11069  lastOffset = freeSpace2ndTo1stEnd;
      +
      11070  }
      +
      11071  }
      +
      11072  }
      +
      11073 
      +
      11074  nextAlloc1stIndex = m_1stNullItemsBeginCount;
      +
      11075  while(lastOffset < freeSpace1stTo2ndEnd)
      +
      11076  {
      +
      11077  // Find next non-null allocation or move nextAllocIndex to the end.
      +
      11078  while(nextAlloc1stIndex < suballoc1stCount &&
      +
      11079  suballocations1st[nextAlloc1stIndex].hAllocation == VK_NULL_HANDLE)
      +
      11080  {
      +
      11081  ++nextAlloc1stIndex;
      +
      11082  }
      +
      11083 
      +
      11084  // Found non-null allocation.
      +
      11085  if(nextAlloc1stIndex < suballoc1stCount)
      +
      11086  {
      +
      11087  const VmaSuballocation& suballoc = suballocations1st[nextAlloc1stIndex];
      +
      11088 
      +
      11089  // 1. Process free space before this allocation.
      +
      11090  if(lastOffset < suballoc.offset)
      +
      11091  {
      +
      11092  // There is free space from lastOffset to suballoc.offset.
      +
      11093  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
      +
      11094  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
      +
      11095  }
      +
      11096 
      +
      11097  // 2. Process this allocation.
      +
      11098  // There is allocation with suballoc.offset, suballoc.size.
      +
      11099  PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.hAllocation);
      11100 
      -
      11101  // Start from offset equal to beginning of free space.
      -
      11102  VkDeviceSize resultOffset = resultBaseOffset;
      -
      11103 
      -
      11104  // Apply VMA_DEBUG_MARGIN at the beginning.
      -
      11105  if(VMA_DEBUG_MARGIN > 0)
      -
      11106  {
      -
      11107  resultOffset += VMA_DEBUG_MARGIN;
      -
      11108  }
      -
      11109 
      -
      11110  // Apply alignment.
      -
      11111  resultOffset = VmaAlignUp(resultOffset, allocAlignment);
      -
      11112 
      -
      11113  // Check previous suballocations for BufferImageGranularity conflicts.
      -
      11114  // Make bigger alignment if necessary.
      -
      11115  if(bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment && !suballocations1st.empty())
      -
      11116  {
      -
      11117  bool bufferImageGranularityConflict = false;
      -
      11118  for(size_t prevSuballocIndex = suballocations1st.size(); prevSuballocIndex--; )
      -
      11119  {
      -
      11120  const VmaSuballocation& prevSuballoc = suballocations1st[prevSuballocIndex];
      -
      11121  if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, resultOffset, bufferImageGranularity))
      -
      11122  {
      -
      11123  if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType))
      -
      11124  {
      -
      11125  bufferImageGranularityConflict = true;
      -
      11126  break;
      -
      11127  }
      -
      11128  }
      -
      11129  else
      -
      11130  // Already on previous page.
      -
      11131  break;
      -
      11132  }
      -
      11133  if(bufferImageGranularityConflict)
      +
      11101  // 3. Prepare for next iteration.
      +
      11102  lastOffset = suballoc.offset + suballoc.size;
      +
      11103  ++nextAlloc1stIndex;
      +
      11104  }
      +
      11105  // We are at the end.
      +
      11106  else
      +
      11107  {
      +
      11108  if(lastOffset < freeSpace1stTo2ndEnd)
      +
      11109  {
      +
      11110  // There is free space from lastOffset to freeSpace1stTo2ndEnd.
      +
      11111  const VkDeviceSize unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset;
      +
      11112  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
      +
      11113  }
      +
      11114 
      +
      11115  // End of loop.
      +
      11116  lastOffset = freeSpace1stTo2ndEnd;
      +
      11117  }
      +
      11118  }
      +
      11119 
      +
      11120  if(m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
      +
      11121  {
      +
      11122  size_t nextAlloc2ndIndex = suballocations2nd.size() - 1;
      +
      11123  while(lastOffset < size)
      +
      11124  {
      +
      11125  // Find next non-null allocation or move nextAlloc2ndIndex to the end.
      +
      11126  while(nextAlloc2ndIndex != SIZE_MAX &&
      +
      11127  suballocations2nd[nextAlloc2ndIndex].hAllocation == VK_NULL_HANDLE)
      +
      11128  {
      +
      11129  --nextAlloc2ndIndex;
      +
      11130  }
      +
      11131 
      +
      11132  // Found non-null allocation.
      +
      11133  if(nextAlloc2ndIndex != SIZE_MAX)
      11134  {
      -
      11135  resultOffset = VmaAlignUp(resultOffset, bufferImageGranularity);
      -
      11136  }
      -
      11137  }
      -
      11138 
      -
      11139  const VkDeviceSize freeSpaceEnd = m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ?
      -
      11140  suballocations2nd.back().offset : size;
      -
      11141 
      -
      11142  // There is enough free space at the end after alignment.
      -
      11143  if(resultOffset + allocSize + VMA_DEBUG_MARGIN <= freeSpaceEnd)
      -
      11144  {
      -
      11145  // Check next suballocations for BufferImageGranularity conflicts.
      -
      11146  // If conflict exists, allocation cannot be made here.
      -
      11147  if((allocSize % bufferImageGranularity || resultOffset % bufferImageGranularity) && m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
      -
      11148  {
      -
      11149  for(size_t nextSuballocIndex = suballocations2nd.size(); nextSuballocIndex--; )
      -
      11150  {
      -
      11151  const VmaSuballocation& nextSuballoc = suballocations2nd[nextSuballocIndex];
      -
      11152  if(VmaBlocksOnSamePage(resultOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
      -
      11153  {
      -
      11154  if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type))
      -
      11155  {
      -
      11156  return false;
      -
      11157  }
      -
      11158  }
      -
      11159  else
      -
      11160  {
      -
      11161  // Already on previous page.
      -
      11162  break;
      -
      11163  }
      -
      11164  }
      +
      11135  const VmaSuballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
      +
      11136 
      +
      11137  // 1. Process free space before this allocation.
      +
      11138  if(lastOffset < suballoc.offset)
      +
      11139  {
      +
      11140  // There is free space from lastOffset to suballoc.offset.
      +
      11141  const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;
      +
      11142  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
      +
      11143  }
      +
      11144 
      +
      11145  // 2. Process this allocation.
      +
      11146  // There is allocation with suballoc.offset, suballoc.size.
      +
      11147  PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.hAllocation);
      +
      11148 
      +
      11149  // 3. Prepare for next iteration.
      +
      11150  lastOffset = suballoc.offset + suballoc.size;
      +
      11151  --nextAlloc2ndIndex;
      +
      11152  }
      +
      11153  // We are at the end.
      +
      11154  else
      +
      11155  {
      +
      11156  if(lastOffset < size)
      +
      11157  {
      +
      11158  // There is free space from lastOffset to size.
      +
      11159  const VkDeviceSize unusedRangeSize = size - lastOffset;
      +
      11160  PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
      +
      11161  }
      +
      11162 
      +
      11163  // End of loop.
      +
      11164  lastOffset = size;
      11165  }
      -
      11166 
      -
      11167  // All tests passed: Success.
      -
      11168  pAllocationRequest->offset = resultOffset;
      -
      11169  pAllocationRequest->sumFreeSize = freeSpaceEnd - resultBaseOffset;
      -
      11170  pAllocationRequest->sumItemSize = 0;
      -
      11171  // pAllocationRequest->item, customData unused.
      -
      11172  pAllocationRequest->type = VmaAllocationRequestType::EndOf1st;
      -
      11173  pAllocationRequest->itemsToMakeLostCount = 0;
      -
      11174  return true;
      -
      11175  }
      -
      11176  }
      -
      11177 
      -
      11178  // Wrap-around to end of 2nd vector. Try to allocate there, watching for the
      -
      11179  // beginning of 1st vector as the end of free space.
      -
      11180  if(m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
      -
      11181  {
      -
      11182  VMA_ASSERT(!suballocations1st.empty());
      -
      11183 
      -
      11184  VkDeviceSize resultBaseOffset = 0;
      -
      11185  if(!suballocations2nd.empty())
      -
      11186  {
      -
      11187  const VmaSuballocation& lastSuballoc = suballocations2nd.back();
      -
      11188  resultBaseOffset = lastSuballoc.offset + lastSuballoc.size;
      -
      11189  }
      -
      11190 
      -
      11191  // Start from offset equal to beginning of free space.
      -
      11192  VkDeviceSize resultOffset = resultBaseOffset;
      -
      11193 
      -
      11194  // Apply VMA_DEBUG_MARGIN at the beginning.
      -
      11195  if(VMA_DEBUG_MARGIN > 0)
      -
      11196  {
      -
      11197  resultOffset += VMA_DEBUG_MARGIN;
      -
      11198  }
      -
      11199 
      -
      11200  // Apply alignment.
      -
      11201  resultOffset = VmaAlignUp(resultOffset, allocAlignment);
      -
      11202 
      -
      11203  // Check previous suballocations for BufferImageGranularity conflicts.
      -
      11204  // Make bigger alignment if necessary.
      -
      11205  if(bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment && !suballocations2nd.empty())
      -
      11206  {
      -
      11207  bool bufferImageGranularityConflict = false;
      -
      11208  for(size_t prevSuballocIndex = suballocations2nd.size(); prevSuballocIndex--; )
      -
      11209  {
      -
      11210  const VmaSuballocation& prevSuballoc = suballocations2nd[prevSuballocIndex];
      -
      11211  if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, resultOffset, bufferImageGranularity))
      -
      11212  {
      -
      11213  if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType))
      -
      11214  {
      -
      11215  bufferImageGranularityConflict = true;
      -
      11216  break;
      -
      11217  }
      -
      11218  }
      -
      11219  else
      -
      11220  // Already on previous page.
      -
      11221  break;
      -
      11222  }
      -
      11223  if(bufferImageGranularityConflict)
      -
      11224  {
      -
      11225  resultOffset = VmaAlignUp(resultOffset, bufferImageGranularity);
      -
      11226  }
      -
      11227  }
      -
      11228 
      -
      11229  pAllocationRequest->itemsToMakeLostCount = 0;
      -
      11230  pAllocationRequest->sumItemSize = 0;
      -
      11231  size_t index1st = m_1stNullItemsBeginCount;
      -
      11232 
      -
      11233  if(canMakeOtherLost)
      -
      11234  {
      -
      11235  while(index1st < suballocations1st.size() &&
      -
      11236  resultOffset + allocSize + VMA_DEBUG_MARGIN > suballocations1st[index1st].offset)
      -
      11237  {
      -
      11238  // Next colliding allocation at the beginning of 1st vector found. Try to make it lost.
      -
      11239  const VmaSuballocation& suballoc = suballocations1st[index1st];
      -
      11240  if(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE)
      -
      11241  {
      -
      11242  // No problem.
      -
      11243  }
      -
      11244  else
      -
      11245  {
      -
      11246  VMA_ASSERT(suballoc.hAllocation != VK_NULL_HANDLE);
      -
      11247  if(suballoc.hAllocation->CanBecomeLost() &&
      -
      11248  suballoc.hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
      -
      11249  {
      -
      11250  ++pAllocationRequest->itemsToMakeLostCount;
      -
      11251  pAllocationRequest->sumItemSize += suballoc.size;
      -
      11252  }
      -
      11253  else
      -
      11254  {
      -
      11255  return false;
      -
      11256  }
      -
      11257  }
      -
      11258  ++index1st;
      -
      11259  }
      -
      11260 
      -
      11261  // Check next suballocations for BufferImageGranularity conflicts.
      -
      11262  // If conflict exists, we must mark more allocations lost or fail.
      -
      11263  if(allocSize % bufferImageGranularity || resultOffset % bufferImageGranularity)
      -
      11264  {
      -
      11265  while(index1st < suballocations1st.size())
      -
      11266  {
      -
      11267  const VmaSuballocation& suballoc = suballocations1st[index1st];
      -
      11268  if(VmaBlocksOnSamePage(resultOffset, allocSize, suballoc.offset, bufferImageGranularity))
      -
      11269  {
      -
      11270  if(suballoc.hAllocation != VK_NULL_HANDLE)
      -
      11271  {
      -
      11272  // Not checking actual VmaIsBufferImageGranularityConflict(allocType, suballoc.type).
      -
      11273  if(suballoc.hAllocation->CanBecomeLost() &&
      -
      11274  suballoc.hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
      -
      11275  {
      -
      11276  ++pAllocationRequest->itemsToMakeLostCount;
      -
      11277  pAllocationRequest->sumItemSize += suballoc.size;
      -
      11278  }
      -
      11279  else
      -
      11280  {
      -
      11281  return false;
      -
      11282  }
      -
      11283  }
      -
      11284  }
      -
      11285  else
      -
      11286  {
      -
      11287  // Already on next page.
      -
      11288  break;
      -
      11289  }
      -
      11290  ++index1st;
      -
      11291  }
      -
      11292  }
      -
      11293 
      -
      11294  // Special case: There is not enough room at the end for this allocation, even after making all from the 1st lost.
      -
      11295  if(index1st == suballocations1st.size() &&
      -
      11296  resultOffset + allocSize + VMA_DEBUG_MARGIN > size)
      -
      11297  {
      -
      11298  // TODO: This is a known bug that it's not yet implemented and the allocation is failing.
      -
      11299  VMA_DEBUG_LOG("Unsupported special case in custom pool with linear allocation algorithm used as ring buffer with allocations that can be lost.");
      -
      11300  }
      -
      11301  }
      -
      11302 
      -
      11303  // There is enough free space at the end after alignment.
      -
      11304  if((index1st == suballocations1st.size() && resultOffset + allocSize + VMA_DEBUG_MARGIN <= size) ||
      -
      11305  (index1st < suballocations1st.size() && resultOffset + allocSize + VMA_DEBUG_MARGIN <= suballocations1st[index1st].offset))
      -
      11306  {
      -
      11307  // Check next suballocations for BufferImageGranularity conflicts.
      -
      11308  // If conflict exists, allocation cannot be made here.
      -
      11309  if(allocSize % bufferImageGranularity || resultOffset % bufferImageGranularity)
      -
      11310  {
      -
      11311  for(size_t nextSuballocIndex = index1st;
      -
      11312  nextSuballocIndex < suballocations1st.size();
      -
      11313  nextSuballocIndex++)
      -
      11314  {
      -
      11315  const VmaSuballocation& nextSuballoc = suballocations1st[nextSuballocIndex];
      -
      11316  if(VmaBlocksOnSamePage(resultOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
      -
      11317  {
      -
      11318  if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type))
      -
      11319  {
      -
      11320  return false;
      -
      11321  }
      -
      11322  }
      -
      11323  else
      -
      11324  {
      -
      11325  // Already on next page.
      -
      11326  break;
      -
      11327  }
      -
      11328  }
      -
      11329  }
      -
      11330 
      -
      11331  // All tests passed: Success.
      -
      11332  pAllocationRequest->offset = resultOffset;
      -
      11333  pAllocationRequest->sumFreeSize =
      -
      11334  (index1st < suballocations1st.size() ? suballocations1st[index1st].offset : size)
      -
      11335  - resultBaseOffset
      -
      11336  - pAllocationRequest->sumItemSize;
      -
      11337  pAllocationRequest->type = VmaAllocationRequestType::EndOf2nd;
      -
      11338  // pAllocationRequest->item, customData unused.
      -
      11339  return true;
      -
      11340  }
      -
      11341  }
      -
      11342 
      -
      11343  return false;
      -
      11344 }
      -
      11345 
      -
      11346 bool VmaBlockMetadata_Linear::MakeRequestedAllocationsLost(
      -
      11347  uint32_t currentFrameIndex,
      -
      11348  uint32_t frameInUseCount,
      -
      11349  VmaAllocationRequest* pAllocationRequest)
      -
      11350 {
      -
      11351  if(pAllocationRequest->itemsToMakeLostCount == 0)
      -
      11352  {
      -
      11353  return true;
      -
      11354  }
      +
      11166  }
      +
      11167  }
      +
      11168 
      +
      11169  PrintDetailedMap_End(json);
      +
      11170 }
      +
      11171 #endif // #if VMA_STATS_STRING_ENABLED
      +
      11172 
      +
      11173 bool VmaBlockMetadata_Linear::CreateAllocationRequest(
      +
      11174  uint32_t currentFrameIndex,
      +
      11175  uint32_t frameInUseCount,
      +
      11176  VkDeviceSize bufferImageGranularity,
      +
      11177  VkDeviceSize allocSize,
      +
      11178  VkDeviceSize allocAlignment,
      +
      11179  bool upperAddress,
      +
      11180  VmaSuballocationType allocType,
      +
      11181  bool canMakeOtherLost,
      +
      11182  uint32_t strategy,
      +
      11183  VmaAllocationRequest* pAllocationRequest)
      +
      11184 {
      +
      11185  VMA_ASSERT(allocSize > 0);
      +
      11186  VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE);
      +
      11187  VMA_ASSERT(pAllocationRequest != VMA_NULL);
      +
      11188  VMA_HEAVY_ASSERT(Validate());
      +
      11189  return upperAddress ?
      +
      11190  CreateAllocationRequest_UpperAddress(
      +
      11191  currentFrameIndex, frameInUseCount, bufferImageGranularity,
      +
      11192  allocSize, allocAlignment, allocType, canMakeOtherLost, strategy, pAllocationRequest) :
      +
      11193  CreateAllocationRequest_LowerAddress(
      +
      11194  currentFrameIndex, frameInUseCount, bufferImageGranularity,
      +
      11195  allocSize, allocAlignment, allocType, canMakeOtherLost, strategy, pAllocationRequest);
      +
      11196 }
      +
      11197 
      +
      11198 bool VmaBlockMetadata_Linear::CreateAllocationRequest_UpperAddress(
      +
      11199  uint32_t currentFrameIndex,
      +
      11200  uint32_t frameInUseCount,
      +
      11201  VkDeviceSize bufferImageGranularity,
      +
      11202  VkDeviceSize allocSize,
      +
      11203  VkDeviceSize allocAlignment,
      +
      11204  VmaSuballocationType allocType,
      +
      11205  bool canMakeOtherLost,
      +
      11206  uint32_t strategy,
      +
      11207  VmaAllocationRequest* pAllocationRequest)
      +
      11208 {
      +
      11209  const VkDeviceSize size = GetSize();
      +
      11210  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      +
      11211  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      +
      11212 
      +
      11213  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
      +
      11214  {
      +
      11215  VMA_ASSERT(0 && "Trying to use pool with linear algorithm as double stack, while it is already being used as ring buffer.");
      +
      11216  return false;
      +
      11217  }
      +
      11218 
      +
      11219  // Try to allocate before 2nd.back(), or end of block if 2nd.empty().
      +
      11220  if(allocSize > size)
      +
      11221  {
      +
      11222  return false;
      +
      11223  }
      +
      11224  VkDeviceSize resultBaseOffset = size - allocSize;
      +
      11225  if(!suballocations2nd.empty())
      +
      11226  {
      +
      11227  const VmaSuballocation& lastSuballoc = suballocations2nd.back();
      +
      11228  resultBaseOffset = lastSuballoc.offset - allocSize;
      +
      11229  if(allocSize > lastSuballoc.offset)
      +
      11230  {
      +
      11231  return false;
      +
      11232  }
      +
      11233  }
      +
      11234 
      +
      11235  // Start from offset equal to end of free space.
      +
      11236  VkDeviceSize resultOffset = resultBaseOffset;
      +
      11237 
      +
      11238  // Apply VMA_DEBUG_MARGIN at the end.
      +
      11239  if(VMA_DEBUG_MARGIN > 0)
      +
      11240  {
      +
      11241  if(resultOffset < VMA_DEBUG_MARGIN)
      +
      11242  {
      +
      11243  return false;
      +
      11244  }
      +
      11245  resultOffset -= VMA_DEBUG_MARGIN;
      +
      11246  }
      +
      11247 
      +
      11248  // Apply alignment.
      +
      11249  resultOffset = VmaAlignDown(resultOffset, allocAlignment);
      +
      11250 
      +
      11251  // Check next suballocations from 2nd for BufferImageGranularity conflicts.
      +
      11252  // Make bigger alignment if necessary.
      +
      11253  if(bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment && !suballocations2nd.empty())
      +
      11254  {
      +
      11255  bool bufferImageGranularityConflict = false;
      +
      11256  for(size_t nextSuballocIndex = suballocations2nd.size(); nextSuballocIndex--; )
      +
      11257  {
      +
      11258  const VmaSuballocation& nextSuballoc = suballocations2nd[nextSuballocIndex];
      +
      11259  if(VmaBlocksOnSamePage(resultOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
      +
      11260  {
      +
      11261  if(VmaIsBufferImageGranularityConflict(nextSuballoc.type, allocType))
      +
      11262  {
      +
      11263  bufferImageGranularityConflict = true;
      +
      11264  break;
      +
      11265  }
      +
      11266  }
      +
      11267  else
      +
      11268  // Already on previous page.
      +
      11269  break;
      +
      11270  }
      +
      11271  if(bufferImageGranularityConflict)
      +
      11272  {
      +
      11273  resultOffset = VmaAlignDown(resultOffset, bufferImageGranularity);
      +
      11274  }
      +
      11275  }
      +
      11276 
      +
      11277  // There is enough free space.
      +
      11278  const VkDeviceSize endOf1st = !suballocations1st.empty() ?
      +
      11279  suballocations1st.back().offset + suballocations1st.back().size :
      +
      11280  0;
      +
      11281  if(endOf1st + VMA_DEBUG_MARGIN <= resultOffset)
      +
      11282  {
      +
      11283  // Check previous suballocations for BufferImageGranularity conflicts.
      +
      11284  // If conflict exists, allocation cannot be made here.
      +
      11285  if(bufferImageGranularity > 1)
      +
      11286  {
      +
      11287  for(size_t prevSuballocIndex = suballocations1st.size(); prevSuballocIndex--; )
      +
      11288  {
      +
      11289  const VmaSuballocation& prevSuballoc = suballocations1st[prevSuballocIndex];
      +
      11290  if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, resultOffset, bufferImageGranularity))
      +
      11291  {
      +
      11292  if(VmaIsBufferImageGranularityConflict(allocType, prevSuballoc.type))
      +
      11293  {
      +
      11294  return false;
      +
      11295  }
      +
      11296  }
      +
      11297  else
      +
      11298  {
      +
      11299  // Already on next page.
      +
      11300  break;
      +
      11301  }
      +
      11302  }
      +
      11303  }
      +
      11304 
      +
      11305  // All tests passed: Success.
      +
      11306  pAllocationRequest->offset = resultOffset;
      +
      11307  pAllocationRequest->sumFreeSize = resultBaseOffset + allocSize - endOf1st;
      +
      11308  pAllocationRequest->sumItemSize = 0;
      +
      11309  // pAllocationRequest->item unused.
      +
      11310  pAllocationRequest->itemsToMakeLostCount = 0;
      +
      11311  pAllocationRequest->type = VmaAllocationRequestType::UpperAddress;
      +
      11312  return true;
      +
      11313  }
      +
      11314 
      +
      11315  return false;
      +
      11316 }
      +
      11317 
      +
      11318 bool VmaBlockMetadata_Linear::CreateAllocationRequest_LowerAddress(
      +
      11319  uint32_t currentFrameIndex,
      +
      11320  uint32_t frameInUseCount,
      +
      11321  VkDeviceSize bufferImageGranularity,
      +
      11322  VkDeviceSize allocSize,
      +
      11323  VkDeviceSize allocAlignment,
      +
      11324  VmaSuballocationType allocType,
      +
      11325  bool canMakeOtherLost,
      +
      11326  uint32_t strategy,
      +
      11327  VmaAllocationRequest* pAllocationRequest)
      +
      11328 {
      +
      11329  const VkDeviceSize size = GetSize();
      +
      11330  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      +
      11331  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      +
      11332 
      +
      11333  if(m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
      +
      11334  {
      +
      11335  // Try to allocate at the end of 1st vector.
      +
      11336 
      +
      11337  VkDeviceSize resultBaseOffset = 0;
      +
      11338  if(!suballocations1st.empty())
      +
      11339  {
      +
      11340  const VmaSuballocation& lastSuballoc = suballocations1st.back();
      +
      11341  resultBaseOffset = lastSuballoc.offset + lastSuballoc.size;
      +
      11342  }
      +
      11343 
      +
      11344  // Start from offset equal to beginning of free space.
      +
      11345  VkDeviceSize resultOffset = resultBaseOffset;
      +
      11346 
      +
      11347  // Apply VMA_DEBUG_MARGIN at the beginning.
      +
      11348  if(VMA_DEBUG_MARGIN > 0)
      +
      11349  {
      +
      11350  resultOffset += VMA_DEBUG_MARGIN;
      +
      11351  }
      +
      11352 
      +
      11353  // Apply alignment.
      +
      11354  resultOffset = VmaAlignUp(resultOffset, allocAlignment);
      11355 
      -
      11356  VMA_ASSERT(m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER);
      -
      11357 
      -
      11358  // We always start from 1st.
      -
      11359  SuballocationVectorType* suballocations = &AccessSuballocations1st();
      -
      11360  size_t index = m_1stNullItemsBeginCount;
      -
      11361  size_t madeLostCount = 0;
      -
      11362  while(madeLostCount < pAllocationRequest->itemsToMakeLostCount)
      -
      11363  {
      -
      11364  if(index == suballocations->size())
      -
      11365  {
      -
      11366  index = 0;
      -
      11367  // If we get to the end of 1st, we wrap around to beginning of 2nd of 1st.
      -
      11368  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
      -
      11369  {
      -
      11370  suballocations = &AccessSuballocations2nd();
      -
      11371  }
      -
      11372  // else: m_2ndVectorMode == SECOND_VECTOR_EMPTY:
      -
      11373  // suballocations continues pointing at AccessSuballocations1st().
      -
      11374  VMA_ASSERT(!suballocations->empty());
      -
      11375  }
      -
      11376  VmaSuballocation& suballoc = (*suballocations)[index];
      -
      11377  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
      -
      11378  {
      -
      11379  VMA_ASSERT(suballoc.hAllocation != VK_NULL_HANDLE);
      -
      11380  VMA_ASSERT(suballoc.hAllocation->CanBecomeLost());
      -
      11381  if(suballoc.hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
      -
      11382  {
      -
      11383  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
      -
      11384  suballoc.hAllocation = VK_NULL_HANDLE;
      -
      11385  m_SumFreeSize += suballoc.size;
      -
      11386  if(suballocations == &AccessSuballocations1st())
      -
      11387  {
      -
      11388  ++m_1stNullItemsMiddleCount;
      -
      11389  }
      -
      11390  else
      -
      11391  {
      -
      11392  ++m_2ndNullItemsCount;
      -
      11393  }
      -
      11394  ++madeLostCount;
      -
      11395  }
      -
      11396  else
      -
      11397  {
      -
      11398  return false;
      -
      11399  }
      -
      11400  }
      -
      11401  ++index;
      -
      11402  }
      -
      11403 
      -
      11404  CleanupAfterFree();
      -
      11405  //VMA_HEAVY_ASSERT(Validate()); // Already called by ClanupAfterFree().
      -
      11406 
      -
      11407  return true;
      -
      11408 }
      +
      11356  // Check previous suballocations for BufferImageGranularity conflicts.
      +
      11357  // Make bigger alignment if necessary.
      +
      11358  if(bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment && !suballocations1st.empty())
      +
      11359  {
      +
      11360  bool bufferImageGranularityConflict = false;
      +
      11361  for(size_t prevSuballocIndex = suballocations1st.size(); prevSuballocIndex--; )
      +
      11362  {
      +
      11363  const VmaSuballocation& prevSuballoc = suballocations1st[prevSuballocIndex];
      +
      11364  if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, resultOffset, bufferImageGranularity))
      +
      11365  {
      +
      11366  if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType))
      +
      11367  {
      +
      11368  bufferImageGranularityConflict = true;
      +
      11369  break;
      +
      11370  }
      +
      11371  }
      +
      11372  else
      +
      11373  // Already on previous page.
      +
      11374  break;
      +
      11375  }
      +
      11376  if(bufferImageGranularityConflict)
      +
      11377  {
      +
      11378  resultOffset = VmaAlignUp(resultOffset, bufferImageGranularity);
      +
      11379  }
      +
      11380  }
      +
      11381 
      +
      11382  const VkDeviceSize freeSpaceEnd = m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ?
      +
      11383  suballocations2nd.back().offset : size;
      +
      11384 
      +
      11385  // There is enough free space at the end after alignment.
      +
      11386  if(resultOffset + allocSize + VMA_DEBUG_MARGIN <= freeSpaceEnd)
      +
      11387  {
      +
      11388  // Check next suballocations for BufferImageGranularity conflicts.
      +
      11389  // If conflict exists, allocation cannot be made here.
      +
      11390  if((allocSize % bufferImageGranularity || resultOffset % bufferImageGranularity) && m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
      +
      11391  {
      +
      11392  for(size_t nextSuballocIndex = suballocations2nd.size(); nextSuballocIndex--; )
      +
      11393  {
      +
      11394  const VmaSuballocation& nextSuballoc = suballocations2nd[nextSuballocIndex];
      +
      11395  if(VmaBlocksOnSamePage(resultOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
      +
      11396  {
      +
      11397  if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type))
      +
      11398  {
      +
      11399  return false;
      +
      11400  }
      +
      11401  }
      +
      11402  else
      +
      11403  {
      +
      11404  // Already on previous page.
      +
      11405  break;
      +
      11406  }
      +
      11407  }
      +
      11408  }
      11409 
      -
      11410 uint32_t VmaBlockMetadata_Linear::MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)
      -
      11411 {
      -
      11412  uint32_t lostAllocationCount = 0;
      -
      11413 
      -
      11414  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      -
      11415  for(size_t i = m_1stNullItemsBeginCount, count = suballocations1st.size(); i < count; ++i)
      -
      11416  {
      -
      11417  VmaSuballocation& suballoc = suballocations1st[i];
      -
      11418  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE &&
      -
      11419  suballoc.hAllocation->CanBecomeLost() &&
      -
      11420  suballoc.hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
      -
      11421  {
      -
      11422  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
      -
      11423  suballoc.hAllocation = VK_NULL_HANDLE;
      -
      11424  ++m_1stNullItemsMiddleCount;
      -
      11425  m_SumFreeSize += suballoc.size;
      -
      11426  ++lostAllocationCount;
      -
      11427  }
      -
      11428  }
      -
      11429 
      -
      11430  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      -
      11431  for(size_t i = 0, count = suballocations2nd.size(); i < count; ++i)
      -
      11432  {
      -
      11433  VmaSuballocation& suballoc = suballocations2nd[i];
      -
      11434  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE &&
      -
      11435  suballoc.hAllocation->CanBecomeLost() &&
      -
      11436  suballoc.hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
      -
      11437  {
      -
      11438  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
      -
      11439  suballoc.hAllocation = VK_NULL_HANDLE;
      -
      11440  ++m_2ndNullItemsCount;
      -
      11441  m_SumFreeSize += suballoc.size;
      -
      11442  ++lostAllocationCount;
      -
      11443  }
      -
      11444  }
      +
      11410  // All tests passed: Success.
      +
      11411  pAllocationRequest->offset = resultOffset;
      +
      11412  pAllocationRequest->sumFreeSize = freeSpaceEnd - resultBaseOffset;
      +
      11413  pAllocationRequest->sumItemSize = 0;
      +
      11414  // pAllocationRequest->item, customData unused.
      +
      11415  pAllocationRequest->type = VmaAllocationRequestType::EndOf1st;
      +
      11416  pAllocationRequest->itemsToMakeLostCount = 0;
      +
      11417  return true;
      +
      11418  }
      +
      11419  }
      +
      11420 
      +
      11421  // Wrap-around to end of 2nd vector. Try to allocate there, watching for the
      +
      11422  // beginning of 1st vector as the end of free space.
      +
      11423  if(m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
      +
      11424  {
      +
      11425  VMA_ASSERT(!suballocations1st.empty());
      +
      11426 
      +
      11427  VkDeviceSize resultBaseOffset = 0;
      +
      11428  if(!suballocations2nd.empty())
      +
      11429  {
      +
      11430  const VmaSuballocation& lastSuballoc = suballocations2nd.back();
      +
      11431  resultBaseOffset = lastSuballoc.offset + lastSuballoc.size;
      +
      11432  }
      +
      11433 
      +
      11434  // Start from offset equal to beginning of free space.
      +
      11435  VkDeviceSize resultOffset = resultBaseOffset;
      +
      11436 
      +
      11437  // Apply VMA_DEBUG_MARGIN at the beginning.
      +
      11438  if(VMA_DEBUG_MARGIN > 0)
      +
      11439  {
      +
      11440  resultOffset += VMA_DEBUG_MARGIN;
      +
      11441  }
      +
      11442 
      +
      11443  // Apply alignment.
      +
      11444  resultOffset = VmaAlignUp(resultOffset, allocAlignment);
      11445 
      -
      11446  if(lostAllocationCount)
      -
      11447  {
      -
      11448  CleanupAfterFree();
      -
      11449  }
      -
      11450 
      -
      11451  return lostAllocationCount;
      -
      11452 }
      -
      11453 
      -
      11454 VkResult VmaBlockMetadata_Linear::CheckCorruption(const void* pBlockData)
      -
      11455 {
      -
      11456  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      -
      11457  for(size_t i = m_1stNullItemsBeginCount, count = suballocations1st.size(); i < count; ++i)
      -
      11458  {
      -
      11459  const VmaSuballocation& suballoc = suballocations1st[i];
      -
      11460  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
      -
      11461  {
      -
      11462  if(!VmaValidateMagicValue(pBlockData, suballoc.offset - VMA_DEBUG_MARGIN))
      -
      11463  {
      -
      11464  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED BEFORE VALIDATED ALLOCATION!");
      -
      11465  return VK_ERROR_VALIDATION_FAILED_EXT;
      -
      11466  }
      -
      11467  if(!VmaValidateMagicValue(pBlockData, suballoc.offset + suballoc.size))
      -
      11468  {
      -
      11469  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!");
      -
      11470  return VK_ERROR_VALIDATION_FAILED_EXT;
      -
      11471  }
      -
      11472  }
      -
      11473  }
      -
      11474 
      -
      11475  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      -
      11476  for(size_t i = 0, count = suballocations2nd.size(); i < count; ++i)
      -
      11477  {
      -
      11478  const VmaSuballocation& suballoc = suballocations2nd[i];
      -
      11479  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
      -
      11480  {
      -
      11481  if(!VmaValidateMagicValue(pBlockData, suballoc.offset - VMA_DEBUG_MARGIN))
      -
      11482  {
      -
      11483  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED BEFORE VALIDATED ALLOCATION!");
      -
      11484  return VK_ERROR_VALIDATION_FAILED_EXT;
      -
      11485  }
      -
      11486  if(!VmaValidateMagicValue(pBlockData, suballoc.offset + suballoc.size))
      -
      11487  {
      -
      11488  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!");
      -
      11489  return VK_ERROR_VALIDATION_FAILED_EXT;
      -
      11490  }
      -
      11491  }
      -
      11492  }
      -
      11493 
      -
      11494  return VK_SUCCESS;
      -
      11495 }
      -
      11496 
      -
      11497 void VmaBlockMetadata_Linear::Alloc(
      -
      11498  const VmaAllocationRequest& request,
      -
      11499  VmaSuballocationType type,
      -
      11500  VkDeviceSize allocSize,
      -
      11501  VmaAllocation hAllocation)
      -
      11502 {
      -
      11503  const VmaSuballocation newSuballoc = { request.offset, allocSize, hAllocation, type };
      -
      11504 
      -
      11505  switch(request.type)
      -
      11506  {
      -
      11507  case VmaAllocationRequestType::UpperAddress:
      -
      11508  {
      -
      11509  VMA_ASSERT(m_2ndVectorMode != SECOND_VECTOR_RING_BUFFER &&
      -
      11510  "CRITICAL ERROR: Trying to use linear allocator as double stack while it was already used as ring buffer.");
      -
      11511  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      -
      11512  suballocations2nd.push_back(newSuballoc);
      -
      11513  m_2ndVectorMode = SECOND_VECTOR_DOUBLE_STACK;
      -
      11514  }
      -
      11515  break;
      -
      11516  case VmaAllocationRequestType::EndOf1st:
      -
      11517  {
      -
      11518  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      -
      11519 
      -
      11520  VMA_ASSERT(suballocations1st.empty() ||
      -
      11521  request.offset >= suballocations1st.back().offset + suballocations1st.back().size);
      -
      11522  // Check if it fits before the end of the block.
      -
      11523  VMA_ASSERT(request.offset + allocSize <= GetSize());
      -
      11524 
      -
      11525  suballocations1st.push_back(newSuballoc);
      -
      11526  }
      -
      11527  break;
      -
      11528  case VmaAllocationRequestType::EndOf2nd:
      -
      11529  {
      -
      11530  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      -
      11531  // New allocation at the end of 2-part ring buffer, so before first allocation from 1st vector.
      -
      11532  VMA_ASSERT(!suballocations1st.empty() &&
      -
      11533  request.offset + allocSize <= suballocations1st[m_1stNullItemsBeginCount].offset);
      -
      11534  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      -
      11535 
      -
      11536  switch(m_2ndVectorMode)
      -
      11537  {
      -
      11538  case SECOND_VECTOR_EMPTY:
      -
      11539  // First allocation from second part ring buffer.
      -
      11540  VMA_ASSERT(suballocations2nd.empty());
      -
      11541  m_2ndVectorMode = SECOND_VECTOR_RING_BUFFER;
      -
      11542  break;
      -
      11543  case SECOND_VECTOR_RING_BUFFER:
      -
      11544  // 2-part ring buffer is already started.
      -
      11545  VMA_ASSERT(!suballocations2nd.empty());
      -
      11546  break;
      -
      11547  case SECOND_VECTOR_DOUBLE_STACK:
      -
      11548  VMA_ASSERT(0 && "CRITICAL ERROR: Trying to use linear allocator as ring buffer while it was already used as double stack.");
      -
      11549  break;
      -
      11550  default:
      -
      11551  VMA_ASSERT(0);
      -
      11552  }
      -
      11553 
      -
      11554  suballocations2nd.push_back(newSuballoc);
      -
      11555  }
      -
      11556  break;
      -
      11557  default:
      -
      11558  VMA_ASSERT(0 && "CRITICAL INTERNAL ERROR.");
      -
      11559  }
      -
      11560 
      -
      11561  m_SumFreeSize -= newSuballoc.size;
      -
      11562 }
      -
      11563 
      -
      11564 void VmaBlockMetadata_Linear::Free(const VmaAllocation allocation)
      -
      11565 {
      -
      11566  FreeAtOffset(allocation->GetOffset());
      -
      11567 }
      -
      11568 
      -
      11569 void VmaBlockMetadata_Linear::FreeAtOffset(VkDeviceSize offset)
      -
      11570 {
      -
      11571  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      -
      11572  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      +
      11446  // Check previous suballocations for BufferImageGranularity conflicts.
      +
      11447  // Make bigger alignment if necessary.
      +
      11448  if(bufferImageGranularity > 1 && bufferImageGranularity != allocAlignment && !suballocations2nd.empty())
      +
      11449  {
      +
      11450  bool bufferImageGranularityConflict = false;
      +
      11451  for(size_t prevSuballocIndex = suballocations2nd.size(); prevSuballocIndex--; )
      +
      11452  {
      +
      11453  const VmaSuballocation& prevSuballoc = suballocations2nd[prevSuballocIndex];
      +
      11454  if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, resultOffset, bufferImageGranularity))
      +
      11455  {
      +
      11456  if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType))
      +
      11457  {
      +
      11458  bufferImageGranularityConflict = true;
      +
      11459  break;
      +
      11460  }
      +
      11461  }
      +
      11462  else
      +
      11463  // Already on previous page.
      +
      11464  break;
      +
      11465  }
      +
      11466  if(bufferImageGranularityConflict)
      +
      11467  {
      +
      11468  resultOffset = VmaAlignUp(resultOffset, bufferImageGranularity);
      +
      11469  }
      +
      11470  }
      +
      11471 
      +
      11472  pAllocationRequest->itemsToMakeLostCount = 0;
      +
      11473  pAllocationRequest->sumItemSize = 0;
      +
      11474  size_t index1st = m_1stNullItemsBeginCount;
      +
      11475 
      +
      11476  if(canMakeOtherLost)
      +
      11477  {
      +
      11478  while(index1st < suballocations1st.size() &&
      +
      11479  resultOffset + allocSize + VMA_DEBUG_MARGIN > suballocations1st[index1st].offset)
      +
      11480  {
      +
      11481  // Next colliding allocation at the beginning of 1st vector found. Try to make it lost.
      +
      11482  const VmaSuballocation& suballoc = suballocations1st[index1st];
      +
      11483  if(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE)
      +
      11484  {
      +
      11485  // No problem.
      +
      11486  }
      +
      11487  else
      +
      11488  {
      +
      11489  VMA_ASSERT(suballoc.hAllocation != VK_NULL_HANDLE);
      +
      11490  if(suballoc.hAllocation->CanBecomeLost() &&
      +
      11491  suballoc.hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
      +
      11492  {
      +
      11493  ++pAllocationRequest->itemsToMakeLostCount;
      +
      11494  pAllocationRequest->sumItemSize += suballoc.size;
      +
      11495  }
      +
      11496  else
      +
      11497  {
      +
      11498  return false;
      +
      11499  }
      +
      11500  }
      +
      11501  ++index1st;
      +
      11502  }
      +
      11503 
      +
      11504  // Check next suballocations for BufferImageGranularity conflicts.
      +
      11505  // If conflict exists, we must mark more allocations lost or fail.
      +
      11506  if(allocSize % bufferImageGranularity || resultOffset % bufferImageGranularity)
      +
      11507  {
      +
      11508  while(index1st < suballocations1st.size())
      +
      11509  {
      +
      11510  const VmaSuballocation& suballoc = suballocations1st[index1st];
      +
      11511  if(VmaBlocksOnSamePage(resultOffset, allocSize, suballoc.offset, bufferImageGranularity))
      +
      11512  {
      +
      11513  if(suballoc.hAllocation != VK_NULL_HANDLE)
      +
      11514  {
      +
      11515  // Not checking actual VmaIsBufferImageGranularityConflict(allocType, suballoc.type).
      +
      11516  if(suballoc.hAllocation->CanBecomeLost() &&
      +
      11517  suballoc.hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
      +
      11518  {
      +
      11519  ++pAllocationRequest->itemsToMakeLostCount;
      +
      11520  pAllocationRequest->sumItemSize += suballoc.size;
      +
      11521  }
      +
      11522  else
      +
      11523  {
      +
      11524  return false;
      +
      11525  }
      +
      11526  }
      +
      11527  }
      +
      11528  else
      +
      11529  {
      +
      11530  // Already on next page.
      +
      11531  break;
      +
      11532  }
      +
      11533  ++index1st;
      +
      11534  }
      +
      11535  }
      +
      11536 
      +
      11537  // Special case: There is not enough room at the end for this allocation, even after making all from the 1st lost.
      +
      11538  if(index1st == suballocations1st.size() &&
      +
      11539  resultOffset + allocSize + VMA_DEBUG_MARGIN > size)
      +
      11540  {
      +
      11541  // TODO: This is a known bug that it's not yet implemented and the allocation is failing.
      +
      11542  VMA_DEBUG_LOG("Unsupported special case in custom pool with linear allocation algorithm used as ring buffer with allocations that can be lost.");
      +
      11543  }
      +
      11544  }
      +
      11545 
      +
      11546  // There is enough free space at the end after alignment.
      +
      11547  if((index1st == suballocations1st.size() && resultOffset + allocSize + VMA_DEBUG_MARGIN <= size) ||
      +
      11548  (index1st < suballocations1st.size() && resultOffset + allocSize + VMA_DEBUG_MARGIN <= suballocations1st[index1st].offset))
      +
      11549  {
      +
      11550  // Check next suballocations for BufferImageGranularity conflicts.
      +
      11551  // If conflict exists, allocation cannot be made here.
      +
      11552  if(allocSize % bufferImageGranularity || resultOffset % bufferImageGranularity)
      +
      11553  {
      +
      11554  for(size_t nextSuballocIndex = index1st;
      +
      11555  nextSuballocIndex < suballocations1st.size();
      +
      11556  nextSuballocIndex++)
      +
      11557  {
      +
      11558  const VmaSuballocation& nextSuballoc = suballocations1st[nextSuballocIndex];
      +
      11559  if(VmaBlocksOnSamePage(resultOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
      +
      11560  {
      +
      11561  if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type))
      +
      11562  {
      +
      11563  return false;
      +
      11564  }
      +
      11565  }
      +
      11566  else
      +
      11567  {
      +
      11568  // Already on next page.
      +
      11569  break;
      +
      11570  }
      +
      11571  }
      +
      11572  }
      11573 
      -
      11574  if(!suballocations1st.empty())
      -
      11575  {
      -
      11576  // First allocation: Mark it as next empty at the beginning.
      -
      11577  VmaSuballocation& firstSuballoc = suballocations1st[m_1stNullItemsBeginCount];
      -
      11578  if(firstSuballoc.offset == offset)
      -
      11579  {
      -
      11580  firstSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
      -
      11581  firstSuballoc.hAllocation = VK_NULL_HANDLE;
      -
      11582  m_SumFreeSize += firstSuballoc.size;
      -
      11583  ++m_1stNullItemsBeginCount;
      -
      11584  CleanupAfterFree();
      -
      11585  return;
      -
      11586  }
      -
      11587  }
      +
      11574  // All tests passed: Success.
      +
      11575  pAllocationRequest->offset = resultOffset;
      +
      11576  pAllocationRequest->sumFreeSize =
      +
      11577  (index1st < suballocations1st.size() ? suballocations1st[index1st].offset : size)
      +
      11578  - resultBaseOffset
      +
      11579  - pAllocationRequest->sumItemSize;
      +
      11580  pAllocationRequest->type = VmaAllocationRequestType::EndOf2nd;
      +
      11581  // pAllocationRequest->item, customData unused.
      +
      11582  return true;
      +
      11583  }
      +
      11584  }
      +
      11585 
      +
      11586  return false;
      +
      11587 }
      11588 
      -
      11589  // Last allocation in 2-part ring buffer or top of upper stack (same logic).
      -
      11590  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER ||
      -
      11591  m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
      -
      11592  {
      -
      11593  VmaSuballocation& lastSuballoc = suballocations2nd.back();
      -
      11594  if(lastSuballoc.offset == offset)
      -
      11595  {
      -
      11596  m_SumFreeSize += lastSuballoc.size;
      -
      11597  suballocations2nd.pop_back();
      -
      11598  CleanupAfterFree();
      -
      11599  return;
      -
      11600  }
      -
      11601  }
      -
      11602  // Last allocation in 1st vector.
      -
      11603  else if(m_2ndVectorMode == SECOND_VECTOR_EMPTY)
      -
      11604  {
      -
      11605  VmaSuballocation& lastSuballoc = suballocations1st.back();
      -
      11606  if(lastSuballoc.offset == offset)
      -
      11607  {
      -
      11608  m_SumFreeSize += lastSuballoc.size;
      -
      11609  suballocations1st.pop_back();
      -
      11610  CleanupAfterFree();
      -
      11611  return;
      -
      11612  }
      -
      11613  }
      -
      11614 
      -
      11615  // Item from the middle of 1st vector.
      -
      11616  {
      -
      11617  VmaSuballocation refSuballoc;
      -
      11618  refSuballoc.offset = offset;
      -
      11619  // Rest of members stays uninitialized intentionally for better performance.
      -
      11620  SuballocationVectorType::iterator it = VmaBinaryFindSorted(
      -
      11621  suballocations1st.begin() + m_1stNullItemsBeginCount,
      -
      11622  suballocations1st.end(),
      -
      11623  refSuballoc,
      -
      11624  VmaSuballocationOffsetLess());
      -
      11625  if(it != suballocations1st.end())
      -
      11626  {
      -
      11627  it->type = VMA_SUBALLOCATION_TYPE_FREE;
      -
      11628  it->hAllocation = VK_NULL_HANDLE;
      -
      11629  ++m_1stNullItemsMiddleCount;
      -
      11630  m_SumFreeSize += it->size;
      -
      11631  CleanupAfterFree();
      -
      11632  return;
      -
      11633  }
      -
      11634  }
      -
      11635 
      -
      11636  if(m_2ndVectorMode != SECOND_VECTOR_EMPTY)
      -
      11637  {
      -
      11638  // Item from the middle of 2nd vector.
      -
      11639  VmaSuballocation refSuballoc;
      -
      11640  refSuballoc.offset = offset;
      -
      11641  // Rest of members stays uninitialized intentionally for better performance.
      -
      11642  SuballocationVectorType::iterator it = m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER ?
      -
      11643  VmaBinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, VmaSuballocationOffsetLess()) :
      -
      11644  VmaBinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, VmaSuballocationOffsetGreater());
      -
      11645  if(it != suballocations2nd.end())
      -
      11646  {
      -
      11647  it->type = VMA_SUBALLOCATION_TYPE_FREE;
      -
      11648  it->hAllocation = VK_NULL_HANDLE;
      -
      11649  ++m_2ndNullItemsCount;
      -
      11650  m_SumFreeSize += it->size;
      -
      11651  CleanupAfterFree();
      -
      11652  return;
      -
      11653  }
      -
      11654  }
      -
      11655 
      -
      11656  VMA_ASSERT(0 && "Allocation to free not found in linear allocator!");
      -
      11657 }
      -
      11658 
      -
      11659 bool VmaBlockMetadata_Linear::ShouldCompact1st() const
      -
      11660 {
      -
      11661  const size_t nullItemCount = m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount;
      -
      11662  const size_t suballocCount = AccessSuballocations1st().size();
      -
      11663  return suballocCount > 32 && nullItemCount * 2 >= (suballocCount - nullItemCount) * 3;
      -
      11664 }
      -
      11665 
      -
      11666 void VmaBlockMetadata_Linear::CleanupAfterFree()
      -
      11667 {
      -
      11668  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      -
      11669  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      -
      11670 
      -
      11671  if(IsEmpty())
      -
      11672  {
      -
      11673  suballocations1st.clear();
      -
      11674  suballocations2nd.clear();
      -
      11675  m_1stNullItemsBeginCount = 0;
      -
      11676  m_1stNullItemsMiddleCount = 0;
      -
      11677  m_2ndNullItemsCount = 0;
      -
      11678  m_2ndVectorMode = SECOND_VECTOR_EMPTY;
      -
      11679  }
      -
      11680  else
      -
      11681  {
      -
      11682  const size_t suballoc1stCount = suballocations1st.size();
      -
      11683  const size_t nullItem1stCount = m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount;
      -
      11684  VMA_ASSERT(nullItem1stCount <= suballoc1stCount);
      -
      11685 
      -
      11686  // Find more null items at the beginning of 1st vector.
      -
      11687  while(m_1stNullItemsBeginCount < suballoc1stCount &&
      -
      11688  suballocations1st[m_1stNullItemsBeginCount].hAllocation == VK_NULL_HANDLE)
      -
      11689  {
      -
      11690  ++m_1stNullItemsBeginCount;
      -
      11691  --m_1stNullItemsMiddleCount;
      -
      11692  }
      +
      11589 bool VmaBlockMetadata_Linear::MakeRequestedAllocationsLost(
      +
      11590  uint32_t currentFrameIndex,
      +
      11591  uint32_t frameInUseCount,
      +
      11592  VmaAllocationRequest* pAllocationRequest)
      +
      11593 {
      +
      11594  if(pAllocationRequest->itemsToMakeLostCount == 0)
      +
      11595  {
      +
      11596  return true;
      +
      11597  }
      +
      11598 
      +
      11599  VMA_ASSERT(m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER);
      +
      11600 
      +
      11601  // We always start from 1st.
      +
      11602  SuballocationVectorType* suballocations = &AccessSuballocations1st();
      +
      11603  size_t index = m_1stNullItemsBeginCount;
      +
      11604  size_t madeLostCount = 0;
      +
      11605  while(madeLostCount < pAllocationRequest->itemsToMakeLostCount)
      +
      11606  {
      +
      11607  if(index == suballocations->size())
      +
      11608  {
      +
      11609  index = 0;
      +
      11610  // If we get to the end of 1st, we wrap around to beginning of 2nd of 1st.
      +
      11611  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
      +
      11612  {
      +
      11613  suballocations = &AccessSuballocations2nd();
      +
      11614  }
      +
      11615  // else: m_2ndVectorMode == SECOND_VECTOR_EMPTY:
      +
      11616  // suballocations continues pointing at AccessSuballocations1st().
      +
      11617  VMA_ASSERT(!suballocations->empty());
      +
      11618  }
      +
      11619  VmaSuballocation& suballoc = (*suballocations)[index];
      +
      11620  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
      +
      11621  {
      +
      11622  VMA_ASSERT(suballoc.hAllocation != VK_NULL_HANDLE);
      +
      11623  VMA_ASSERT(suballoc.hAllocation->CanBecomeLost());
      +
      11624  if(suballoc.hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
      +
      11625  {
      +
      11626  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
      +
      11627  suballoc.hAllocation = VK_NULL_HANDLE;
      +
      11628  m_SumFreeSize += suballoc.size;
      +
      11629  if(suballocations == &AccessSuballocations1st())
      +
      11630  {
      +
      11631  ++m_1stNullItemsMiddleCount;
      +
      11632  }
      +
      11633  else
      +
      11634  {
      +
      11635  ++m_2ndNullItemsCount;
      +
      11636  }
      +
      11637  ++madeLostCount;
      +
      11638  }
      +
      11639  else
      +
      11640  {
      +
      11641  return false;
      +
      11642  }
      +
      11643  }
      +
      11644  ++index;
      +
      11645  }
      +
      11646 
      +
      11647  CleanupAfterFree();
      +
      11648  //VMA_HEAVY_ASSERT(Validate()); // Already called by ClanupAfterFree().
      +
      11649 
      +
      11650  return true;
      +
      11651 }
      +
      11652 
      +
      11653 uint32_t VmaBlockMetadata_Linear::MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)
      +
      11654 {
      +
      11655  uint32_t lostAllocationCount = 0;
      +
      11656 
      +
      11657  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      +
      11658  for(size_t i = m_1stNullItemsBeginCount, count = suballocations1st.size(); i < count; ++i)
      +
      11659  {
      +
      11660  VmaSuballocation& suballoc = suballocations1st[i];
      +
      11661  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE &&
      +
      11662  suballoc.hAllocation->CanBecomeLost() &&
      +
      11663  suballoc.hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
      +
      11664  {
      +
      11665  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
      +
      11666  suballoc.hAllocation = VK_NULL_HANDLE;
      +
      11667  ++m_1stNullItemsMiddleCount;
      +
      11668  m_SumFreeSize += suballoc.size;
      +
      11669  ++lostAllocationCount;
      +
      11670  }
      +
      11671  }
      +
      11672 
      +
      11673  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      +
      11674  for(size_t i = 0, count = suballocations2nd.size(); i < count; ++i)
      +
      11675  {
      +
      11676  VmaSuballocation& suballoc = suballocations2nd[i];
      +
      11677  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE &&
      +
      11678  suballoc.hAllocation->CanBecomeLost() &&
      +
      11679  suballoc.hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
      +
      11680  {
      +
      11681  suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
      +
      11682  suballoc.hAllocation = VK_NULL_HANDLE;
      +
      11683  ++m_2ndNullItemsCount;
      +
      11684  m_SumFreeSize += suballoc.size;
      +
      11685  ++lostAllocationCount;
      +
      11686  }
      +
      11687  }
      +
      11688 
      +
      11689  if(lostAllocationCount)
      +
      11690  {
      +
      11691  CleanupAfterFree();
      +
      11692  }
      11693 
      -
      11694  // Find more null items at the end of 1st vector.
      -
      11695  while(m_1stNullItemsMiddleCount > 0 &&
      -
      11696  suballocations1st.back().hAllocation == VK_NULL_HANDLE)
      -
      11697  {
      -
      11698  --m_1stNullItemsMiddleCount;
      -
      11699  suballocations1st.pop_back();
      -
      11700  }
      -
      11701 
      -
      11702  // Find more null items at the end of 2nd vector.
      -
      11703  while(m_2ndNullItemsCount > 0 &&
      -
      11704  suballocations2nd.back().hAllocation == VK_NULL_HANDLE)
      -
      11705  {
      -
      11706  --m_2ndNullItemsCount;
      -
      11707  suballocations2nd.pop_back();
      -
      11708  }
      -
      11709 
      -
      11710  // Find more null items at the beginning of 2nd vector.
      -
      11711  while(m_2ndNullItemsCount > 0 &&
      -
      11712  suballocations2nd[0].hAllocation == VK_NULL_HANDLE)
      -
      11713  {
      -
      11714  --m_2ndNullItemsCount;
      -
      11715  VmaVectorRemove(suballocations2nd, 0);
      -
      11716  }
      +
      11694  return lostAllocationCount;
      +
      11695 }
      +
      11696 
      +
      11697 VkResult VmaBlockMetadata_Linear::CheckCorruption(const void* pBlockData)
      +
      11698 {
      +
      11699  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      +
      11700  for(size_t i = m_1stNullItemsBeginCount, count = suballocations1st.size(); i < count; ++i)
      +
      11701  {
      +
      11702  const VmaSuballocation& suballoc = suballocations1st[i];
      +
      11703  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
      +
      11704  {
      +
      11705  if(!VmaValidateMagicValue(pBlockData, suballoc.offset - VMA_DEBUG_MARGIN))
      +
      11706  {
      +
      11707  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED BEFORE VALIDATED ALLOCATION!");
      +
      11708  return VK_ERROR_VALIDATION_FAILED_EXT;
      +
      11709  }
      +
      11710  if(!VmaValidateMagicValue(pBlockData, suballoc.offset + suballoc.size))
      +
      11711  {
      +
      11712  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!");
      +
      11713  return VK_ERROR_VALIDATION_FAILED_EXT;
      +
      11714  }
      +
      11715  }
      +
      11716  }
      11717 
      -
      11718  if(ShouldCompact1st())
      -
      11719  {
      -
      11720  const size_t nonNullItemCount = suballoc1stCount - nullItem1stCount;
      -
      11721  size_t srcIndex = m_1stNullItemsBeginCount;
      -
      11722  for(size_t dstIndex = 0; dstIndex < nonNullItemCount; ++dstIndex)
      -
      11723  {
      -
      11724  while(suballocations1st[srcIndex].hAllocation == VK_NULL_HANDLE)
      -
      11725  {
      -
      11726  ++srcIndex;
      -
      11727  }
      -
      11728  if(dstIndex != srcIndex)
      -
      11729  {
      -
      11730  suballocations1st[dstIndex] = suballocations1st[srcIndex];
      -
      11731  }
      -
      11732  ++srcIndex;
      +
      11718  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      +
      11719  for(size_t i = 0, count = suballocations2nd.size(); i < count; ++i)
      +
      11720  {
      +
      11721  const VmaSuballocation& suballoc = suballocations2nd[i];
      +
      11722  if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
      +
      11723  {
      +
      11724  if(!VmaValidateMagicValue(pBlockData, suballoc.offset - VMA_DEBUG_MARGIN))
      +
      11725  {
      +
      11726  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED BEFORE VALIDATED ALLOCATION!");
      +
      11727  return VK_ERROR_VALIDATION_FAILED_EXT;
      +
      11728  }
      +
      11729  if(!VmaValidateMagicValue(pBlockData, suballoc.offset + suballoc.size))
      +
      11730  {
      +
      11731  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER VALIDATED ALLOCATION!");
      +
      11732  return VK_ERROR_VALIDATION_FAILED_EXT;
      11733  }
      -
      11734  suballocations1st.resize(nonNullItemCount);
      -
      11735  m_1stNullItemsBeginCount = 0;
      -
      11736  m_1stNullItemsMiddleCount = 0;
      -
      11737  }
      -
      11738 
      -
      11739  // 2nd vector became empty.
      -
      11740  if(suballocations2nd.empty())
      -
      11741  {
      -
      11742  m_2ndVectorMode = SECOND_VECTOR_EMPTY;
      -
      11743  }
      -
      11744 
      -
      11745  // 1st vector became empty.
      -
      11746  if(suballocations1st.size() - m_1stNullItemsBeginCount == 0)
      -
      11747  {
      -
      11748  suballocations1st.clear();
      -
      11749  m_1stNullItemsBeginCount = 0;
      -
      11750 
      -
      11751  if(!suballocations2nd.empty() && m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
      -
      11752  {
      -
      11753  // Swap 1st with 2nd. Now 2nd is empty.
      -
      11754  m_2ndVectorMode = SECOND_VECTOR_EMPTY;
      -
      11755  m_1stNullItemsMiddleCount = m_2ndNullItemsCount;
      -
      11756  while(m_1stNullItemsBeginCount < suballocations2nd.size() &&
      -
      11757  suballocations2nd[m_1stNullItemsBeginCount].hAllocation == VK_NULL_HANDLE)
      -
      11758  {
      -
      11759  ++m_1stNullItemsBeginCount;
      -
      11760  --m_1stNullItemsMiddleCount;
      -
      11761  }
      -
      11762  m_2ndNullItemsCount = 0;
      -
      11763  m_1stVectorIndex ^= 1;
      -
      11764  }
      -
      11765  }
      -
      11766  }
      +
      11734  }
      +
      11735  }
      +
      11736 
      +
      11737  return VK_SUCCESS;
      +
      11738 }
      +
      11739 
      +
      11740 void VmaBlockMetadata_Linear::Alloc(
      +
      11741  const VmaAllocationRequest& request,
      +
      11742  VmaSuballocationType type,
      +
      11743  VkDeviceSize allocSize,
      +
      11744  VmaAllocation hAllocation)
      +
      11745 {
      +
      11746  const VmaSuballocation newSuballoc = { request.offset, allocSize, hAllocation, type };
      +
      11747 
      +
      11748  switch(request.type)
      +
      11749  {
      +
      11750  case VmaAllocationRequestType::UpperAddress:
      +
      11751  {
      +
      11752  VMA_ASSERT(m_2ndVectorMode != SECOND_VECTOR_RING_BUFFER &&
      +
      11753  "CRITICAL ERROR: Trying to use linear allocator as double stack while it was already used as ring buffer.");
      +
      11754  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      +
      11755  suballocations2nd.push_back(newSuballoc);
      +
      11756  m_2ndVectorMode = SECOND_VECTOR_DOUBLE_STACK;
      +
      11757  }
      +
      11758  break;
      +
      11759  case VmaAllocationRequestType::EndOf1st:
      +
      11760  {
      +
      11761  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      +
      11762 
      +
      11763  VMA_ASSERT(suballocations1st.empty() ||
      +
      11764  request.offset >= suballocations1st.back().offset + suballocations1st.back().size);
      +
      11765  // Check if it fits before the end of the block.
      +
      11766  VMA_ASSERT(request.offset + allocSize <= GetSize());
      11767 
      -
      11768  VMA_HEAVY_ASSERT(Validate());
      -
      11769 }
      -
      11770 
      -
      11771 
      -
      11773 // class VmaBlockMetadata_Buddy
      -
      11774 
      -
      11775 VmaBlockMetadata_Buddy::VmaBlockMetadata_Buddy(VmaAllocator hAllocator) :
      -
      11776  VmaBlockMetadata(hAllocator),
      -
      11777  m_Root(VMA_NULL),
      -
      11778  m_AllocationCount(0),
      -
      11779  m_FreeCount(1),
      -
      11780  m_SumFreeSize(0)
      -
      11781 {
      -
      11782  memset(m_FreeList, 0, sizeof(m_FreeList));
      -
      11783 }
      -
      11784 
      -
      11785 VmaBlockMetadata_Buddy::~VmaBlockMetadata_Buddy()
      -
      11786 {
      -
      11787  DeleteNode(m_Root);
      -
      11788 }
      -
      11789 
      -
      11790 void VmaBlockMetadata_Buddy::Init(VkDeviceSize size)
      -
      11791 {
      -
      11792  VmaBlockMetadata::Init(size);
      -
      11793 
      -
      11794  m_UsableSize = VmaPrevPow2(size);
      -
      11795  m_SumFreeSize = m_UsableSize;
      +
      11768  suballocations1st.push_back(newSuballoc);
      +
      11769  }
      +
      11770  break;
      +
      11771  case VmaAllocationRequestType::EndOf2nd:
      +
      11772  {
      +
      11773  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      +
      11774  // New allocation at the end of 2-part ring buffer, so before first allocation from 1st vector.
      +
      11775  VMA_ASSERT(!suballocations1st.empty() &&
      +
      11776  request.offset + allocSize <= suballocations1st[m_1stNullItemsBeginCount].offset);
      +
      11777  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      +
      11778 
      +
      11779  switch(m_2ndVectorMode)
      +
      11780  {
      +
      11781  case SECOND_VECTOR_EMPTY:
      +
      11782  // First allocation from second part ring buffer.
      +
      11783  VMA_ASSERT(suballocations2nd.empty());
      +
      11784  m_2ndVectorMode = SECOND_VECTOR_RING_BUFFER;
      +
      11785  break;
      +
      11786  case SECOND_VECTOR_RING_BUFFER:
      +
      11787  // 2-part ring buffer is already started.
      +
      11788  VMA_ASSERT(!suballocations2nd.empty());
      +
      11789  break;
      +
      11790  case SECOND_VECTOR_DOUBLE_STACK:
      +
      11791  VMA_ASSERT(0 && "CRITICAL ERROR: Trying to use linear allocator as ring buffer while it was already used as double stack.");
      +
      11792  break;
      +
      11793  default:
      +
      11794  VMA_ASSERT(0);
      +
      11795  }
      11796 
      -
      11797  // Calculate m_LevelCount.
      -
      11798  m_LevelCount = 1;
      -
      11799  while(m_LevelCount < MAX_LEVELS &&
      -
      11800  LevelToNodeSize(m_LevelCount) >= MIN_NODE_SIZE)
      -
      11801  {
      -
      11802  ++m_LevelCount;
      -
      11803  }
      -
      11804 
      -
      11805  Node* rootNode = vma_new(GetAllocationCallbacks(), Node)();
      -
      11806  rootNode->offset = 0;
      -
      11807  rootNode->type = Node::TYPE_FREE;
      -
      11808  rootNode->parent = VMA_NULL;
      -
      11809  rootNode->buddy = VMA_NULL;
      -
      11810 
      -
      11811  m_Root = rootNode;
      -
      11812  AddToFreeListFront(0, rootNode);
      -
      11813 }
      -
      11814 
      -
      11815 bool VmaBlockMetadata_Buddy::Validate() const
      -
      11816 {
      -
      11817  // Validate tree.
      -
      11818  ValidationContext ctx;
      -
      11819  if(!ValidateNode(ctx, VMA_NULL, m_Root, 0, LevelToNodeSize(0)))
      -
      11820  {
      -
      11821  VMA_VALIDATE(false && "ValidateNode failed.");
      -
      11822  }
      -
      11823  VMA_VALIDATE(m_AllocationCount == ctx.calculatedAllocationCount);
      -
      11824  VMA_VALIDATE(m_SumFreeSize == ctx.calculatedSumFreeSize);
      -
      11825 
      -
      11826  // Validate free node lists.
      -
      11827  for(uint32_t level = 0; level < m_LevelCount; ++level)
      -
      11828  {
      -
      11829  VMA_VALIDATE(m_FreeList[level].front == VMA_NULL ||
      -
      11830  m_FreeList[level].front->free.prev == VMA_NULL);
      +
      11797  suballocations2nd.push_back(newSuballoc);
      +
      11798  }
      +
      11799  break;
      +
      11800  default:
      +
      11801  VMA_ASSERT(0 && "CRITICAL INTERNAL ERROR.");
      +
      11802  }
      +
      11803 
      +
      11804  m_SumFreeSize -= newSuballoc.size;
      +
      11805 }
      +
      11806 
      +
      11807 void VmaBlockMetadata_Linear::Free(const VmaAllocation allocation)
      +
      11808 {
      +
      11809  FreeAtOffset(allocation->GetOffset());
      +
      11810 }
      +
      11811 
      +
      11812 void VmaBlockMetadata_Linear::FreeAtOffset(VkDeviceSize offset)
      +
      11813 {
      +
      11814  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      +
      11815  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      +
      11816 
      +
      11817  if(!suballocations1st.empty())
      +
      11818  {
      +
      11819  // First allocation: Mark it as next empty at the beginning.
      +
      11820  VmaSuballocation& firstSuballoc = suballocations1st[m_1stNullItemsBeginCount];
      +
      11821  if(firstSuballoc.offset == offset)
      +
      11822  {
      +
      11823  firstSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
      +
      11824  firstSuballoc.hAllocation = VK_NULL_HANDLE;
      +
      11825  m_SumFreeSize += firstSuballoc.size;
      +
      11826  ++m_1stNullItemsBeginCount;
      +
      11827  CleanupAfterFree();
      +
      11828  return;
      +
      11829  }
      +
      11830  }
      11831 
      -
      11832  for(Node* node = m_FreeList[level].front;
      -
      11833  node != VMA_NULL;
      -
      11834  node = node->free.next)
      -
      11835  {
      -
      11836  VMA_VALIDATE(node->type == Node::TYPE_FREE);
      -
      11837 
      -
      11838  if(node->free.next == VMA_NULL)
      -
      11839  {
      -
      11840  VMA_VALIDATE(m_FreeList[level].back == node);
      -
      11841  }
      -
      11842  else
      -
      11843  {
      -
      11844  VMA_VALIDATE(node->free.next->free.prev == node);
      -
      11845  }
      -
      11846  }
      -
      11847  }
      -
      11848 
      -
      11849  // Validate that free lists ar higher levels are empty.
      -
      11850  for(uint32_t level = m_LevelCount; level < MAX_LEVELS; ++level)
      -
      11851  {
      -
      11852  VMA_VALIDATE(m_FreeList[level].front == VMA_NULL && m_FreeList[level].back == VMA_NULL);
      -
      11853  }
      -
      11854 
      -
      11855  return true;
      -
      11856 }
      +
      11832  // Last allocation in 2-part ring buffer or top of upper stack (same logic).
      +
      11833  if(m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER ||
      +
      11834  m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
      +
      11835  {
      +
      11836  VmaSuballocation& lastSuballoc = suballocations2nd.back();
      +
      11837  if(lastSuballoc.offset == offset)
      +
      11838  {
      +
      11839  m_SumFreeSize += lastSuballoc.size;
      +
      11840  suballocations2nd.pop_back();
      +
      11841  CleanupAfterFree();
      +
      11842  return;
      +
      11843  }
      +
      11844  }
      +
      11845  // Last allocation in 1st vector.
      +
      11846  else if(m_2ndVectorMode == SECOND_VECTOR_EMPTY)
      +
      11847  {
      +
      11848  VmaSuballocation& lastSuballoc = suballocations1st.back();
      +
      11849  if(lastSuballoc.offset == offset)
      +
      11850  {
      +
      11851  m_SumFreeSize += lastSuballoc.size;
      +
      11852  suballocations1st.pop_back();
      +
      11853  CleanupAfterFree();
      +
      11854  return;
      +
      11855  }
      +
      11856  }
      11857 
      -
      11858 VkDeviceSize VmaBlockMetadata_Buddy::GetUnusedRangeSizeMax() const
      -
      11859 {
      -
      11860  for(uint32_t level = 0; level < m_LevelCount; ++level)
      -
      11861  {
      -
      11862  if(m_FreeList[level].front != VMA_NULL)
      -
      11863  {
      -
      11864  return LevelToNodeSize(level);
      -
      11865  }
      -
      11866  }
      -
      11867  return 0;
      -
      11868 }
      -
      11869 
      -
      11870 void VmaBlockMetadata_Buddy::CalcAllocationStatInfo(VmaStatInfo& outInfo) const
      -
      11871 {
      -
      11872  const VkDeviceSize unusableSize = GetUnusableSize();
      -
      11873 
      -
      11874  outInfo.blockCount = 1;
      -
      11875 
      -
      11876  outInfo.allocationCount = outInfo.unusedRangeCount = 0;
      -
      11877  outInfo.usedBytes = outInfo.unusedBytes = 0;
      +
      11858  // Item from the middle of 1st vector.
      +
      11859  {
      +
      11860  VmaSuballocation refSuballoc;
      +
      11861  refSuballoc.offset = offset;
      +
      11862  // Rest of members stays uninitialized intentionally for better performance.
      +
      11863  SuballocationVectorType::iterator it = VmaBinaryFindSorted(
      +
      11864  suballocations1st.begin() + m_1stNullItemsBeginCount,
      +
      11865  suballocations1st.end(),
      +
      11866  refSuballoc,
      +
      11867  VmaSuballocationOffsetLess());
      +
      11868  if(it != suballocations1st.end())
      +
      11869  {
      +
      11870  it->type = VMA_SUBALLOCATION_TYPE_FREE;
      +
      11871  it->hAllocation = VK_NULL_HANDLE;
      +
      11872  ++m_1stNullItemsMiddleCount;
      +
      11873  m_SumFreeSize += it->size;
      +
      11874  CleanupAfterFree();
      +
      11875  return;
      +
      11876  }
      +
      11877  }
      11878 
      -
      11879  outInfo.allocationSizeMax = outInfo.unusedRangeSizeMax = 0;
      -
      11880  outInfo.allocationSizeMin = outInfo.unusedRangeSizeMin = UINT64_MAX;
      -
      11881  outInfo.allocationSizeAvg = outInfo.unusedRangeSizeAvg = 0; // Unused.
      -
      11882 
      -
      11883  CalcAllocationStatInfoNode(outInfo, m_Root, LevelToNodeSize(0));
      -
      11884 
      -
      11885  if(unusableSize > 0)
      -
      11886  {
      -
      11887  ++outInfo.unusedRangeCount;
      -
      11888  outInfo.unusedBytes += unusableSize;
      -
      11889  outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, unusableSize);
      -
      11890  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusableSize);
      -
      11891  }
      -
      11892 }
      -
      11893 
      -
      11894 void VmaBlockMetadata_Buddy::AddPoolStats(VmaPoolStats& inoutStats) const
      -
      11895 {
      -
      11896  const VkDeviceSize unusableSize = GetUnusableSize();
      -
      11897 
      -
      11898  inoutStats.size += GetSize();
      -
      11899  inoutStats.unusedSize += m_SumFreeSize + unusableSize;
      -
      11900  inoutStats.allocationCount += m_AllocationCount;
      -
      11901  inoutStats.unusedRangeCount += m_FreeCount;
      -
      11902  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, GetUnusedRangeSizeMax());
      -
      11903 
      -
      11904  if(unusableSize > 0)
      -
      11905  {
      -
      11906  ++inoutStats.unusedRangeCount;
      -
      11907  // Not updating inoutStats.unusedRangeSizeMax with unusableSize because this space is not available for allocations.
      -
      11908  }
      -
      11909 }
      -
      11910 
      -
      11911 #if VMA_STATS_STRING_ENABLED
      -
      11912 
      -
      11913 void VmaBlockMetadata_Buddy::PrintDetailedMap(class VmaJsonWriter& json) const
      -
      11914 {
      -
      11915  // TODO optimize
      -
      11916  VmaStatInfo stat;
      -
      11917  CalcAllocationStatInfo(stat);
      -
      11918 
      -
      11919  PrintDetailedMap_Begin(
      -
      11920  json,
      -
      11921  stat.unusedBytes,
      -
      11922  stat.allocationCount,
      -
      11923  stat.unusedRangeCount);
      -
      11924 
      -
      11925  PrintDetailedMapNode(json, m_Root, LevelToNodeSize(0));
      -
      11926 
      -
      11927  const VkDeviceSize unusableSize = GetUnusableSize();
      -
      11928  if(unusableSize > 0)
      -
      11929  {
      -
      11930  PrintDetailedMap_UnusedRange(json,
      -
      11931  m_UsableSize, // offset
      -
      11932  unusableSize); // size
      -
      11933  }
      -
      11934 
      -
      11935  PrintDetailedMap_End(json);
      -
      11936 }
      -
      11937 
      -
      11938 #endif // #if VMA_STATS_STRING_ENABLED
      -
      11939 
      -
      11940 bool VmaBlockMetadata_Buddy::CreateAllocationRequest(
      -
      11941  uint32_t currentFrameIndex,
      -
      11942  uint32_t frameInUseCount,
      -
      11943  VkDeviceSize bufferImageGranularity,
      -
      11944  VkDeviceSize allocSize,
      -
      11945  VkDeviceSize allocAlignment,
      -
      11946  bool upperAddress,
      -
      11947  VmaSuballocationType allocType,
      -
      11948  bool canMakeOtherLost,
      -
      11949  uint32_t strategy,
      -
      11950  VmaAllocationRequest* pAllocationRequest)
      -
      11951 {
      -
      11952  VMA_ASSERT(!upperAddress && "VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT can be used only with linear algorithm.");
      -
      11953 
      -
      11954  // Simple way to respect bufferImageGranularity. May be optimized some day.
      -
      11955  // Whenever it might be an OPTIMAL image...
      -
      11956  if(allocType == VMA_SUBALLOCATION_TYPE_UNKNOWN ||
      -
      11957  allocType == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN ||
      -
      11958  allocType == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL)
      -
      11959  {
      -
      11960  allocAlignment = VMA_MAX(allocAlignment, bufferImageGranularity);
      -
      11961  allocSize = VMA_MAX(allocSize, bufferImageGranularity);
      -
      11962  }
      -
      11963 
      -
      11964  if(allocSize > m_UsableSize)
      -
      11965  {
      -
      11966  return false;
      -
      11967  }
      -
      11968 
      -
      11969  const uint32_t targetLevel = AllocSizeToLevel(allocSize);
      -
      11970  for(uint32_t level = targetLevel + 1; level--; )
      -
      11971  {
      -
      11972  for(Node* freeNode = m_FreeList[level].front;
      -
      11973  freeNode != VMA_NULL;
      -
      11974  freeNode = freeNode->free.next)
      -
      11975  {
      -
      11976  if(freeNode->offset % allocAlignment == 0)
      -
      11977  {
      -
      11978  pAllocationRequest->type = VmaAllocationRequestType::Normal;
      -
      11979  pAllocationRequest->offset = freeNode->offset;
      -
      11980  pAllocationRequest->sumFreeSize = LevelToNodeSize(level);
      -
      11981  pAllocationRequest->sumItemSize = 0;
      -
      11982  pAllocationRequest->itemsToMakeLostCount = 0;
      -
      11983  pAllocationRequest->customData = (void*)(uintptr_t)level;
      -
      11984  return true;
      -
      11985  }
      +
      11879  if(m_2ndVectorMode != SECOND_VECTOR_EMPTY)
      +
      11880  {
      +
      11881  // Item from the middle of 2nd vector.
      +
      11882  VmaSuballocation refSuballoc;
      +
      11883  refSuballoc.offset = offset;
      +
      11884  // Rest of members stays uninitialized intentionally for better performance.
      +
      11885  SuballocationVectorType::iterator it = m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER ?
      +
      11886  VmaBinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, VmaSuballocationOffsetLess()) :
      +
      11887  VmaBinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, VmaSuballocationOffsetGreater());
      +
      11888  if(it != suballocations2nd.end())
      +
      11889  {
      +
      11890  it->type = VMA_SUBALLOCATION_TYPE_FREE;
      +
      11891  it->hAllocation = VK_NULL_HANDLE;
      +
      11892  ++m_2ndNullItemsCount;
      +
      11893  m_SumFreeSize += it->size;
      +
      11894  CleanupAfterFree();
      +
      11895  return;
      +
      11896  }
      +
      11897  }
      +
      11898 
      +
      11899  VMA_ASSERT(0 && "Allocation to free not found in linear allocator!");
      +
      11900 }
      +
      11901 
      +
      11902 bool VmaBlockMetadata_Linear::ShouldCompact1st() const
      +
      11903 {
      +
      11904  const size_t nullItemCount = m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount;
      +
      11905  const size_t suballocCount = AccessSuballocations1st().size();
      +
      11906  return suballocCount > 32 && nullItemCount * 2 >= (suballocCount - nullItemCount) * 3;
      +
      11907 }
      +
      11908 
      +
      11909 void VmaBlockMetadata_Linear::CleanupAfterFree()
      +
      11910 {
      +
      11911  SuballocationVectorType& suballocations1st = AccessSuballocations1st();
      +
      11912  SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
      +
      11913 
      +
      11914  if(IsEmpty())
      +
      11915  {
      +
      11916  suballocations1st.clear();
      +
      11917  suballocations2nd.clear();
      +
      11918  m_1stNullItemsBeginCount = 0;
      +
      11919  m_1stNullItemsMiddleCount = 0;
      +
      11920  m_2ndNullItemsCount = 0;
      +
      11921  m_2ndVectorMode = SECOND_VECTOR_EMPTY;
      +
      11922  }
      +
      11923  else
      +
      11924  {
      +
      11925  const size_t suballoc1stCount = suballocations1st.size();
      +
      11926  const size_t nullItem1stCount = m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount;
      +
      11927  VMA_ASSERT(nullItem1stCount <= suballoc1stCount);
      +
      11928 
      +
      11929  // Find more null items at the beginning of 1st vector.
      +
      11930  while(m_1stNullItemsBeginCount < suballoc1stCount &&
      +
      11931  suballocations1st[m_1stNullItemsBeginCount].hAllocation == VK_NULL_HANDLE)
      +
      11932  {
      +
      11933  ++m_1stNullItemsBeginCount;
      +
      11934  --m_1stNullItemsMiddleCount;
      +
      11935  }
      +
      11936 
      +
      11937  // Find more null items at the end of 1st vector.
      +
      11938  while(m_1stNullItemsMiddleCount > 0 &&
      +
      11939  suballocations1st.back().hAllocation == VK_NULL_HANDLE)
      +
      11940  {
      +
      11941  --m_1stNullItemsMiddleCount;
      +
      11942  suballocations1st.pop_back();
      +
      11943  }
      +
      11944 
      +
      11945  // Find more null items at the end of 2nd vector.
      +
      11946  while(m_2ndNullItemsCount > 0 &&
      +
      11947  suballocations2nd.back().hAllocation == VK_NULL_HANDLE)
      +
      11948  {
      +
      11949  --m_2ndNullItemsCount;
      +
      11950  suballocations2nd.pop_back();
      +
      11951  }
      +
      11952 
      +
      11953  // Find more null items at the beginning of 2nd vector.
      +
      11954  while(m_2ndNullItemsCount > 0 &&
      +
      11955  suballocations2nd[0].hAllocation == VK_NULL_HANDLE)
      +
      11956  {
      +
      11957  --m_2ndNullItemsCount;
      +
      11958  VmaVectorRemove(suballocations2nd, 0);
      +
      11959  }
      +
      11960 
      +
      11961  if(ShouldCompact1st())
      +
      11962  {
      +
      11963  const size_t nonNullItemCount = suballoc1stCount - nullItem1stCount;
      +
      11964  size_t srcIndex = m_1stNullItemsBeginCount;
      +
      11965  for(size_t dstIndex = 0; dstIndex < nonNullItemCount; ++dstIndex)
      +
      11966  {
      +
      11967  while(suballocations1st[srcIndex].hAllocation == VK_NULL_HANDLE)
      +
      11968  {
      +
      11969  ++srcIndex;
      +
      11970  }
      +
      11971  if(dstIndex != srcIndex)
      +
      11972  {
      +
      11973  suballocations1st[dstIndex] = suballocations1st[srcIndex];
      +
      11974  }
      +
      11975  ++srcIndex;
      +
      11976  }
      +
      11977  suballocations1st.resize(nonNullItemCount);
      +
      11978  m_1stNullItemsBeginCount = 0;
      +
      11979  m_1stNullItemsMiddleCount = 0;
      +
      11980  }
      +
      11981 
      +
      11982  // 2nd vector became empty.
      +
      11983  if(suballocations2nd.empty())
      +
      11984  {
      +
      11985  m_2ndVectorMode = SECOND_VECTOR_EMPTY;
      11986  }
      -
      11987  }
      -
      11988 
      -
      11989  return false;
      -
      11990 }
      -
      11991 
      -
      11992 bool VmaBlockMetadata_Buddy::MakeRequestedAllocationsLost(
      -
      11993  uint32_t currentFrameIndex,
      -
      11994  uint32_t frameInUseCount,
      -
      11995  VmaAllocationRequest* pAllocationRequest)
      -
      11996 {
      -
      11997  /*
      -
      11998  Lost allocations are not supported in buddy allocator at the moment.
      -
      11999  Support might be added in the future.
      -
      12000  */
      -
      12001  return pAllocationRequest->itemsToMakeLostCount == 0;
      -
      12002 }
      -
      12003 
      -
      12004 uint32_t VmaBlockMetadata_Buddy::MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)
      -
      12005 {
      -
      12006  /*
      -
      12007  Lost allocations are not supported in buddy allocator at the moment.
      -
      12008  Support might be added in the future.
      -
      12009  */
      -
      12010  return 0;
      -
      12011 }
      -
      12012 
      -
      12013 void VmaBlockMetadata_Buddy::Alloc(
      -
      12014  const VmaAllocationRequest& request,
      -
      12015  VmaSuballocationType type,
      -
      12016  VkDeviceSize allocSize,
      -
      12017  VmaAllocation hAllocation)
      -
      12018 {
      -
      12019  VMA_ASSERT(request.type == VmaAllocationRequestType::Normal);
      -
      12020 
      -
      12021  const uint32_t targetLevel = AllocSizeToLevel(allocSize);
      -
      12022  uint32_t currLevel = (uint32_t)(uintptr_t)request.customData;
      -
      12023 
      -
      12024  Node* currNode = m_FreeList[currLevel].front;
      -
      12025  VMA_ASSERT(currNode != VMA_NULL && currNode->type == Node::TYPE_FREE);
      -
      12026  while(currNode->offset != request.offset)
      -
      12027  {
      -
      12028  currNode = currNode->free.next;
      -
      12029  VMA_ASSERT(currNode != VMA_NULL && currNode->type == Node::TYPE_FREE);
      -
      12030  }
      -
      12031 
      -
      12032  // Go down, splitting free nodes.
      -
      12033  while(currLevel < targetLevel)
      -
      12034  {
      -
      12035  // currNode is already first free node at currLevel.
      -
      12036  // Remove it from list of free nodes at this currLevel.
      -
      12037  RemoveFromFreeList(currLevel, currNode);
      -
      12038 
      -
      12039  const uint32_t childrenLevel = currLevel + 1;
      -
      12040 
      -
      12041  // Create two free sub-nodes.
      -
      12042  Node* leftChild = vma_new(GetAllocationCallbacks(), Node)();
      -
      12043  Node* rightChild = vma_new(GetAllocationCallbacks(), Node)();
      -
      12044 
      -
      12045  leftChild->offset = currNode->offset;
      -
      12046  leftChild->type = Node::TYPE_FREE;
      -
      12047  leftChild->parent = currNode;
      -
      12048  leftChild->buddy = rightChild;
      -
      12049 
      -
      12050  rightChild->offset = currNode->offset + LevelToNodeSize(childrenLevel);
      -
      12051  rightChild->type = Node::TYPE_FREE;
      -
      12052  rightChild->parent = currNode;
      -
      12053  rightChild->buddy = leftChild;
      -
      12054 
      -
      12055  // Convert current currNode to split type.
      -
      12056  currNode->type = Node::TYPE_SPLIT;
      -
      12057  currNode->split.leftChild = leftChild;
      -
      12058 
      -
      12059  // Add child nodes to free list. Order is important!
      -
      12060  AddToFreeListFront(childrenLevel, rightChild);
      -
      12061  AddToFreeListFront(childrenLevel, leftChild);
      -
      12062 
      -
      12063  ++m_FreeCount;
      -
      12064  //m_SumFreeSize -= LevelToNodeSize(currLevel) % 2; // Useful only when level node sizes can be non power of 2.
      -
      12065  ++currLevel;
      -
      12066  currNode = m_FreeList[currLevel].front;
      -
      12067 
      -
      12068  /*
      -
      12069  We can be sure that currNode, as left child of node previously split,
      -
      12070  also fullfills the alignment requirement.
      -
      12071  */
      -
      12072  }
      -
      12073 
      -
      12074  // Remove from free list.
      -
      12075  VMA_ASSERT(currLevel == targetLevel &&
      -
      12076  currNode != VMA_NULL &&
      -
      12077  currNode->type == Node::TYPE_FREE);
      -
      12078  RemoveFromFreeList(currLevel, currNode);
      -
      12079 
      -
      12080  // Convert to allocation node.
      -
      12081  currNode->type = Node::TYPE_ALLOCATION;
      -
      12082  currNode->allocation.alloc = hAllocation;
      -
      12083 
      -
      12084  ++m_AllocationCount;
      -
      12085  --m_FreeCount;
      -
      12086  m_SumFreeSize -= allocSize;
      -
      12087 }
      -
      12088 
      -
      12089 void VmaBlockMetadata_Buddy::DeleteNode(Node* node)
      -
      12090 {
      -
      12091  if(node->type == Node::TYPE_SPLIT)
      -
      12092  {
      -
      12093  DeleteNode(node->split.leftChild->buddy);
      -
      12094  DeleteNode(node->split.leftChild);
      -
      12095  }
      -
      12096 
      -
      12097  vma_delete(GetAllocationCallbacks(), node);
      -
      12098 }
      -
      12099 
      -
      12100 bool VmaBlockMetadata_Buddy::ValidateNode(ValidationContext& ctx, const Node* parent, const Node* curr, uint32_t level, VkDeviceSize levelNodeSize) const
      -
      12101 {
      -
      12102  VMA_VALIDATE(level < m_LevelCount);
      -
      12103  VMA_VALIDATE(curr->parent == parent);
      -
      12104  VMA_VALIDATE((curr->buddy == VMA_NULL) == (parent == VMA_NULL));
      -
      12105  VMA_VALIDATE(curr->buddy == VMA_NULL || curr->buddy->buddy == curr);
      -
      12106  switch(curr->type)
      -
      12107  {
      -
      12108  case Node::TYPE_FREE:
      -
      12109  // curr->free.prev, next are validated separately.
      -
      12110  ctx.calculatedSumFreeSize += levelNodeSize;
      -
      12111  ++ctx.calculatedFreeCount;
      -
      12112  break;
      -
      12113  case Node::TYPE_ALLOCATION:
      -
      12114  ++ctx.calculatedAllocationCount;
      -
      12115  ctx.calculatedSumFreeSize += levelNodeSize - curr->allocation.alloc->GetSize();
      -
      12116  VMA_VALIDATE(curr->allocation.alloc != VK_NULL_HANDLE);
      -
      12117  break;
      -
      12118  case Node::TYPE_SPLIT:
      -
      12119  {
      -
      12120  const uint32_t childrenLevel = level + 1;
      -
      12121  const VkDeviceSize childrenLevelNodeSize = levelNodeSize / 2;
      -
      12122  const Node* const leftChild = curr->split.leftChild;
      -
      12123  VMA_VALIDATE(leftChild != VMA_NULL);
      -
      12124  VMA_VALIDATE(leftChild->offset == curr->offset);
      -
      12125  if(!ValidateNode(ctx, curr, leftChild, childrenLevel, childrenLevelNodeSize))
      -
      12126  {
      -
      12127  VMA_VALIDATE(false && "ValidateNode for left child failed.");
      -
      12128  }
      -
      12129  const Node* const rightChild = leftChild->buddy;
      -
      12130  VMA_VALIDATE(rightChild->offset == curr->offset + childrenLevelNodeSize);
      -
      12131  if(!ValidateNode(ctx, curr, rightChild, childrenLevel, childrenLevelNodeSize))
      -
      12132  {
      -
      12133  VMA_VALIDATE(false && "ValidateNode for right child failed.");
      -
      12134  }
      -
      12135  }
      -
      12136  break;
      -
      12137  default:
      -
      12138  return false;
      -
      12139  }
      +
      11987 
      +
      11988  // 1st vector became empty.
      +
      11989  if(suballocations1st.size() - m_1stNullItemsBeginCount == 0)
      +
      11990  {
      +
      11991  suballocations1st.clear();
      +
      11992  m_1stNullItemsBeginCount = 0;
      +
      11993 
      +
      11994  if(!suballocations2nd.empty() && m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
      +
      11995  {
      +
      11996  // Swap 1st with 2nd. Now 2nd is empty.
      +
      11997  m_2ndVectorMode = SECOND_VECTOR_EMPTY;
      +
      11998  m_1stNullItemsMiddleCount = m_2ndNullItemsCount;
      +
      11999  while(m_1stNullItemsBeginCount < suballocations2nd.size() &&
      +
      12000  suballocations2nd[m_1stNullItemsBeginCount].hAllocation == VK_NULL_HANDLE)
      +
      12001  {
      +
      12002  ++m_1stNullItemsBeginCount;
      +
      12003  --m_1stNullItemsMiddleCount;
      +
      12004  }
      +
      12005  m_2ndNullItemsCount = 0;
      +
      12006  m_1stVectorIndex ^= 1;
      +
      12007  }
      +
      12008  }
      +
      12009  }
      +
      12010 
      +
      12011  VMA_HEAVY_ASSERT(Validate());
      +
      12012 }
      +
      12013 
      +
      12014 
      +
      12016 // class VmaBlockMetadata_Buddy
      +
      12017 
      +
      12018 VmaBlockMetadata_Buddy::VmaBlockMetadata_Buddy(VmaAllocator hAllocator) :
      +
      12019  VmaBlockMetadata(hAllocator),
      +
      12020  m_Root(VMA_NULL),
      +
      12021  m_AllocationCount(0),
      +
      12022  m_FreeCount(1),
      +
      12023  m_SumFreeSize(0)
      +
      12024 {
      +
      12025  memset(m_FreeList, 0, sizeof(m_FreeList));
      +
      12026 }
      +
      12027 
      +
      12028 VmaBlockMetadata_Buddy::~VmaBlockMetadata_Buddy()
      +
      12029 {
      +
      12030  DeleteNode(m_Root);
      +
      12031 }
      +
      12032 
      +
      12033 void VmaBlockMetadata_Buddy::Init(VkDeviceSize size)
      +
      12034 {
      +
      12035  VmaBlockMetadata::Init(size);
      +
      12036 
      +
      12037  m_UsableSize = VmaPrevPow2(size);
      +
      12038  m_SumFreeSize = m_UsableSize;
      +
      12039 
      +
      12040  // Calculate m_LevelCount.
      +
      12041  m_LevelCount = 1;
      +
      12042  while(m_LevelCount < MAX_LEVELS &&
      +
      12043  LevelToNodeSize(m_LevelCount) >= MIN_NODE_SIZE)
      +
      12044  {
      +
      12045  ++m_LevelCount;
      +
      12046  }
      +
      12047 
      +
      12048  Node* rootNode = vma_new(GetAllocationCallbacks(), Node)();
      +
      12049  rootNode->offset = 0;
      +
      12050  rootNode->type = Node::TYPE_FREE;
      +
      12051  rootNode->parent = VMA_NULL;
      +
      12052  rootNode->buddy = VMA_NULL;
      +
      12053 
      +
      12054  m_Root = rootNode;
      +
      12055  AddToFreeListFront(0, rootNode);
      +
      12056 }
      +
      12057 
      +
      12058 bool VmaBlockMetadata_Buddy::Validate() const
      +
      12059 {
      +
      12060  // Validate tree.
      +
      12061  ValidationContext ctx;
      +
      12062  if(!ValidateNode(ctx, VMA_NULL, m_Root, 0, LevelToNodeSize(0)))
      +
      12063  {
      +
      12064  VMA_VALIDATE(false && "ValidateNode failed.");
      +
      12065  }
      +
      12066  VMA_VALIDATE(m_AllocationCount == ctx.calculatedAllocationCount);
      +
      12067  VMA_VALIDATE(m_SumFreeSize == ctx.calculatedSumFreeSize);
      +
      12068 
      +
      12069  // Validate free node lists.
      +
      12070  for(uint32_t level = 0; level < m_LevelCount; ++level)
      +
      12071  {
      +
      12072  VMA_VALIDATE(m_FreeList[level].front == VMA_NULL ||
      +
      12073  m_FreeList[level].front->free.prev == VMA_NULL);
      +
      12074 
      +
      12075  for(Node* node = m_FreeList[level].front;
      +
      12076  node != VMA_NULL;
      +
      12077  node = node->free.next)
      +
      12078  {
      +
      12079  VMA_VALIDATE(node->type == Node::TYPE_FREE);
      +
      12080 
      +
      12081  if(node->free.next == VMA_NULL)
      +
      12082  {
      +
      12083  VMA_VALIDATE(m_FreeList[level].back == node);
      +
      12084  }
      +
      12085  else
      +
      12086  {
      +
      12087  VMA_VALIDATE(node->free.next->free.prev == node);
      +
      12088  }
      +
      12089  }
      +
      12090  }
      +
      12091 
      +
      12092  // Validate that free lists ar higher levels are empty.
      +
      12093  for(uint32_t level = m_LevelCount; level < MAX_LEVELS; ++level)
      +
      12094  {
      +
      12095  VMA_VALIDATE(m_FreeList[level].front == VMA_NULL && m_FreeList[level].back == VMA_NULL);
      +
      12096  }
      +
      12097 
      +
      12098  return true;
      +
      12099 }
      +
      12100 
      +
      12101 VkDeviceSize VmaBlockMetadata_Buddy::GetUnusedRangeSizeMax() const
      +
      12102 {
      +
      12103  for(uint32_t level = 0; level < m_LevelCount; ++level)
      +
      12104  {
      +
      12105  if(m_FreeList[level].front != VMA_NULL)
      +
      12106  {
      +
      12107  return LevelToNodeSize(level);
      +
      12108  }
      +
      12109  }
      +
      12110  return 0;
      +
      12111 }
      +
      12112 
      +
      12113 void VmaBlockMetadata_Buddy::CalcAllocationStatInfo(VmaStatInfo& outInfo) const
      +
      12114 {
      +
      12115  const VkDeviceSize unusableSize = GetUnusableSize();
      +
      12116 
      +
      12117  outInfo.blockCount = 1;
      +
      12118 
      +
      12119  outInfo.allocationCount = outInfo.unusedRangeCount = 0;
      +
      12120  outInfo.usedBytes = outInfo.unusedBytes = 0;
      +
      12121 
      +
      12122  outInfo.allocationSizeMax = outInfo.unusedRangeSizeMax = 0;
      +
      12123  outInfo.allocationSizeMin = outInfo.unusedRangeSizeMin = UINT64_MAX;
      +
      12124  outInfo.allocationSizeAvg = outInfo.unusedRangeSizeAvg = 0; // Unused.
      +
      12125 
      +
      12126  CalcAllocationStatInfoNode(outInfo, m_Root, LevelToNodeSize(0));
      +
      12127 
      +
      12128  if(unusableSize > 0)
      +
      12129  {
      +
      12130  ++outInfo.unusedRangeCount;
      +
      12131  outInfo.unusedBytes += unusableSize;
      +
      12132  outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, unusableSize);
      +
      12133  outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusableSize);
      +
      12134  }
      +
      12135 }
      +
      12136 
      +
      12137 void VmaBlockMetadata_Buddy::AddPoolStats(VmaPoolStats& inoutStats) const
      +
      12138 {
      +
      12139  const VkDeviceSize unusableSize = GetUnusableSize();
      12140 
      -
      12141  return true;
      -
      12142 }
      -
      12143 
      -
      12144 uint32_t VmaBlockMetadata_Buddy::AllocSizeToLevel(VkDeviceSize allocSize) const
      -
      12145 {
      -
      12146  // I know this could be optimized somehow e.g. by using std::log2p1 from C++20.
      -
      12147  uint32_t level = 0;
      -
      12148  VkDeviceSize currLevelNodeSize = m_UsableSize;
      -
      12149  VkDeviceSize nextLevelNodeSize = currLevelNodeSize >> 1;
      -
      12150  while(allocSize <= nextLevelNodeSize && level + 1 < m_LevelCount)
      -
      12151  {
      -
      12152  ++level;
      -
      12153  currLevelNodeSize = nextLevelNodeSize;
      -
      12154  nextLevelNodeSize = currLevelNodeSize >> 1;
      -
      12155  }
      -
      12156  return level;
      -
      12157 }
      -
      12158 
      -
      12159 void VmaBlockMetadata_Buddy::FreeAtOffset(VmaAllocation alloc, VkDeviceSize offset)
      -
      12160 {
      -
      12161  // Find node and level.
      -
      12162  Node* node = m_Root;
      -
      12163  VkDeviceSize nodeOffset = 0;
      -
      12164  uint32_t level = 0;
      -
      12165  VkDeviceSize levelNodeSize = LevelToNodeSize(0);
      -
      12166  while(node->type == Node::TYPE_SPLIT)
      -
      12167  {
      -
      12168  const VkDeviceSize nextLevelSize = levelNodeSize >> 1;
      -
      12169  if(offset < nodeOffset + nextLevelSize)
      -
      12170  {
      -
      12171  node = node->split.leftChild;
      -
      12172  }
      -
      12173  else
      -
      12174  {
      -
      12175  node = node->split.leftChild->buddy;
      -
      12176  nodeOffset += nextLevelSize;
      -
      12177  }
      -
      12178  ++level;
      -
      12179  levelNodeSize = nextLevelSize;
      -
      12180  }
      -
      12181 
      -
      12182  VMA_ASSERT(node != VMA_NULL && node->type == Node::TYPE_ALLOCATION);
      -
      12183  VMA_ASSERT(alloc == VK_NULL_HANDLE || node->allocation.alloc == alloc);
      -
      12184 
      -
      12185  ++m_FreeCount;
      -
      12186  --m_AllocationCount;
      -
      12187  m_SumFreeSize += alloc->GetSize();
      -
      12188 
      -
      12189  node->type = Node::TYPE_FREE;
      -
      12190 
      -
      12191  // Join free nodes if possible.
      -
      12192  while(level > 0 && node->buddy->type == Node::TYPE_FREE)
      -
      12193  {
      -
      12194  RemoveFromFreeList(level, node->buddy);
      -
      12195  Node* const parent = node->parent;
      +
      12141  inoutStats.size += GetSize();
      +
      12142  inoutStats.unusedSize += m_SumFreeSize + unusableSize;
      +
      12143  inoutStats.allocationCount += m_AllocationCount;
      +
      12144  inoutStats.unusedRangeCount += m_FreeCount;
      +
      12145  inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, GetUnusedRangeSizeMax());
      +
      12146 
      +
      12147  if(unusableSize > 0)
      +
      12148  {
      +
      12149  ++inoutStats.unusedRangeCount;
      +
      12150  // Not updating inoutStats.unusedRangeSizeMax with unusableSize because this space is not available for allocations.
      +
      12151  }
      +
      12152 }
      +
      12153 
      +
      12154 #if VMA_STATS_STRING_ENABLED
      +
      12155 
      +
      12156 void VmaBlockMetadata_Buddy::PrintDetailedMap(class VmaJsonWriter& json) const
      +
      12157 {
      +
      12158  // TODO optimize
      +
      12159  VmaStatInfo stat;
      +
      12160  CalcAllocationStatInfo(stat);
      +
      12161 
      +
      12162  PrintDetailedMap_Begin(
      +
      12163  json,
      +
      12164  stat.unusedBytes,
      +
      12165  stat.allocationCount,
      +
      12166  stat.unusedRangeCount);
      +
      12167 
      +
      12168  PrintDetailedMapNode(json, m_Root, LevelToNodeSize(0));
      +
      12169 
      +
      12170  const VkDeviceSize unusableSize = GetUnusableSize();
      +
      12171  if(unusableSize > 0)
      +
      12172  {
      +
      12173  PrintDetailedMap_UnusedRange(json,
      +
      12174  m_UsableSize, // offset
      +
      12175  unusableSize); // size
      +
      12176  }
      +
      12177 
      +
      12178  PrintDetailedMap_End(json);
      +
      12179 }
      +
      12180 
      +
      12181 #endif // #if VMA_STATS_STRING_ENABLED
      +
      12182 
      +
      12183 bool VmaBlockMetadata_Buddy::CreateAllocationRequest(
      +
      12184  uint32_t currentFrameIndex,
      +
      12185  uint32_t frameInUseCount,
      +
      12186  VkDeviceSize bufferImageGranularity,
      +
      12187  VkDeviceSize allocSize,
      +
      12188  VkDeviceSize allocAlignment,
      +
      12189  bool upperAddress,
      +
      12190  VmaSuballocationType allocType,
      +
      12191  bool canMakeOtherLost,
      +
      12192  uint32_t strategy,
      +
      12193  VmaAllocationRequest* pAllocationRequest)
      +
      12194 {
      +
      12195  VMA_ASSERT(!upperAddress && "VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT can be used only with linear algorithm.");
      12196 
      -
      12197  vma_delete(GetAllocationCallbacks(), node->buddy);
      -
      12198  vma_delete(GetAllocationCallbacks(), node);
      -
      12199  parent->type = Node::TYPE_FREE;
      -
      12200 
      -
      12201  node = parent;
      -
      12202  --level;
      -
      12203  //m_SumFreeSize += LevelToNodeSize(level) % 2; // Useful only when level node sizes can be non power of 2.
      -
      12204  --m_FreeCount;
      +
      12197  // Simple way to respect bufferImageGranularity. May be optimized some day.
      +
      12198  // Whenever it might be an OPTIMAL image...
      +
      12199  if(allocType == VMA_SUBALLOCATION_TYPE_UNKNOWN ||
      +
      12200  allocType == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN ||
      +
      12201  allocType == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL)
      +
      12202  {
      +
      12203  allocAlignment = VMA_MAX(allocAlignment, bufferImageGranularity);
      +
      12204  allocSize = VMA_MAX(allocSize, bufferImageGranularity);
      12205  }
      12206 
      -
      12207  AddToFreeListFront(level, node);
      -
      12208 }
      -
      12209 
      -
      12210 void VmaBlockMetadata_Buddy::CalcAllocationStatInfoNode(VmaStatInfo& outInfo, const Node* node, VkDeviceSize levelNodeSize) const
      -
      12211 {
      -
      12212  switch(node->type)
      -
      12213  {
      -
      12214  case Node::TYPE_FREE:
      -
      12215  ++outInfo.unusedRangeCount;
      -
      12216  outInfo.unusedBytes += levelNodeSize;
      -
      12217  outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, levelNodeSize);
      -
      12218  outInfo.unusedRangeSizeMin = VMA_MAX(outInfo.unusedRangeSizeMin, levelNodeSize);
      -
      12219  break;
      -
      12220  case Node::TYPE_ALLOCATION:
      -
      12221  {
      -
      12222  const VkDeviceSize allocSize = node->allocation.alloc->GetSize();
      -
      12223  ++outInfo.allocationCount;
      -
      12224  outInfo.usedBytes += allocSize;
      -
      12225  outInfo.allocationSizeMax = VMA_MAX(outInfo.allocationSizeMax, allocSize);
      -
      12226  outInfo.allocationSizeMin = VMA_MAX(outInfo.allocationSizeMin, allocSize);
      -
      12227 
      -
      12228  const VkDeviceSize unusedRangeSize = levelNodeSize - allocSize;
      -
      12229  if(unusedRangeSize > 0)
      -
      12230  {
      -
      12231  ++outInfo.unusedRangeCount;
      -
      12232  outInfo.unusedBytes += unusedRangeSize;
      -
      12233  outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, unusedRangeSize);
      -
      12234  outInfo.unusedRangeSizeMin = VMA_MAX(outInfo.unusedRangeSizeMin, unusedRangeSize);
      -
      12235  }
      -
      12236  }
      -
      12237  break;
      -
      12238  case Node::TYPE_SPLIT:
      -
      12239  {
      -
      12240  const VkDeviceSize childrenNodeSize = levelNodeSize / 2;
      -
      12241  const Node* const leftChild = node->split.leftChild;
      -
      12242  CalcAllocationStatInfoNode(outInfo, leftChild, childrenNodeSize);
      -
      12243  const Node* const rightChild = leftChild->buddy;
      -
      12244  CalcAllocationStatInfoNode(outInfo, rightChild, childrenNodeSize);
      -
      12245  }
      -
      12246  break;
      -
      12247  default:
      -
      12248  VMA_ASSERT(0);
      -
      12249  }
      -
      12250 }
      -
      12251 
      -
      12252 void VmaBlockMetadata_Buddy::AddToFreeListFront(uint32_t level, Node* node)
      -
      12253 {
      -
      12254  VMA_ASSERT(node->type == Node::TYPE_FREE);
      +
      12207  if(allocSize > m_UsableSize)
      +
      12208  {
      +
      12209  return false;
      +
      12210  }
      +
      12211 
      +
      12212  const uint32_t targetLevel = AllocSizeToLevel(allocSize);
      +
      12213  for(uint32_t level = targetLevel + 1; level--; )
      +
      12214  {
      +
      12215  for(Node* freeNode = m_FreeList[level].front;
      +
      12216  freeNode != VMA_NULL;
      +
      12217  freeNode = freeNode->free.next)
      +
      12218  {
      +
      12219  if(freeNode->offset % allocAlignment == 0)
      +
      12220  {
      +
      12221  pAllocationRequest->type = VmaAllocationRequestType::Normal;
      +
      12222  pAllocationRequest->offset = freeNode->offset;
      +
      12223  pAllocationRequest->sumFreeSize = LevelToNodeSize(level);
      +
      12224  pAllocationRequest->sumItemSize = 0;
      +
      12225  pAllocationRequest->itemsToMakeLostCount = 0;
      +
      12226  pAllocationRequest->customData = (void*)(uintptr_t)level;
      +
      12227  return true;
      +
      12228  }
      +
      12229  }
      +
      12230  }
      +
      12231 
      +
      12232  return false;
      +
      12233 }
      +
      12234 
      +
      12235 bool VmaBlockMetadata_Buddy::MakeRequestedAllocationsLost(
      +
      12236  uint32_t currentFrameIndex,
      +
      12237  uint32_t frameInUseCount,
      +
      12238  VmaAllocationRequest* pAllocationRequest)
      +
      12239 {
      +
      12240  /*
      +
      12241  Lost allocations are not supported in buddy allocator at the moment.
      +
      12242  Support might be added in the future.
      +
      12243  */
      +
      12244  return pAllocationRequest->itemsToMakeLostCount == 0;
      +
      12245 }
      +
      12246 
      +
      12247 uint32_t VmaBlockMetadata_Buddy::MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)
      +
      12248 {
      +
      12249  /*
      +
      12250  Lost allocations are not supported in buddy allocator at the moment.
      +
      12251  Support might be added in the future.
      +
      12252  */
      +
      12253  return 0;
      +
      12254 }
      12255 
      -
      12256  // List is empty.
      -
      12257  Node* const frontNode = m_FreeList[level].front;
      -
      12258  if(frontNode == VMA_NULL)
      -
      12259  {
      -
      12260  VMA_ASSERT(m_FreeList[level].back == VMA_NULL);
      -
      12261  node->free.prev = node->free.next = VMA_NULL;
      -
      12262  m_FreeList[level].front = m_FreeList[level].back = node;
      -
      12263  }
      -
      12264  else
      -
      12265  {
      -
      12266  VMA_ASSERT(frontNode->free.prev == VMA_NULL);
      -
      12267  node->free.prev = VMA_NULL;
      -
      12268  node->free.next = frontNode;
      -
      12269  frontNode->free.prev = node;
      -
      12270  m_FreeList[level].front = node;
      -
      12271  }
      -
      12272 }
      -
      12273 
      -
      12274 void VmaBlockMetadata_Buddy::RemoveFromFreeList(uint32_t level, Node* node)
      -
      12275 {
      -
      12276  VMA_ASSERT(m_FreeList[level].front != VMA_NULL);
      -
      12277 
      -
      12278  // It is at the front.
      -
      12279  if(node->free.prev == VMA_NULL)
      -
      12280  {
      -
      12281  VMA_ASSERT(m_FreeList[level].front == node);
      -
      12282  m_FreeList[level].front = node->free.next;
      -
      12283  }
      -
      12284  else
      -
      12285  {
      -
      12286  Node* const prevFreeNode = node->free.prev;
      -
      12287  VMA_ASSERT(prevFreeNode->free.next == node);
      -
      12288  prevFreeNode->free.next = node->free.next;
      -
      12289  }
      -
      12290 
      -
      12291  // It is at the back.
      -
      12292  if(node->free.next == VMA_NULL)
      -
      12293  {
      -
      12294  VMA_ASSERT(m_FreeList[level].back == node);
      -
      12295  m_FreeList[level].back = node->free.prev;
      -
      12296  }
      -
      12297  else
      -
      12298  {
      -
      12299  Node* const nextFreeNode = node->free.next;
      -
      12300  VMA_ASSERT(nextFreeNode->free.prev == node);
      -
      12301  nextFreeNode->free.prev = node->free.prev;
      -
      12302  }
      -
      12303 }
      -
      12304 
      -
      12305 #if VMA_STATS_STRING_ENABLED
      -
      12306 void VmaBlockMetadata_Buddy::PrintDetailedMapNode(class VmaJsonWriter& json, const Node* node, VkDeviceSize levelNodeSize) const
      -
      12307 {
      -
      12308  switch(node->type)
      -
      12309  {
      -
      12310  case Node::TYPE_FREE:
      -
      12311  PrintDetailedMap_UnusedRange(json, node->offset, levelNodeSize);
      -
      12312  break;
      -
      12313  case Node::TYPE_ALLOCATION:
      -
      12314  {
      -
      12315  PrintDetailedMap_Allocation(json, node->offset, node->allocation.alloc);
      -
      12316  const VkDeviceSize allocSize = node->allocation.alloc->GetSize();
      -
      12317  if(allocSize < levelNodeSize)
      -
      12318  {
      -
      12319  PrintDetailedMap_UnusedRange(json, node->offset + allocSize, levelNodeSize - allocSize);
      -
      12320  }
      -
      12321  }
      -
      12322  break;
      -
      12323  case Node::TYPE_SPLIT:
      -
      12324  {
      -
      12325  const VkDeviceSize childrenNodeSize = levelNodeSize / 2;
      -
      12326  const Node* const leftChild = node->split.leftChild;
      -
      12327  PrintDetailedMapNode(json, leftChild, childrenNodeSize);
      -
      12328  const Node* const rightChild = leftChild->buddy;
      -
      12329  PrintDetailedMapNode(json, rightChild, childrenNodeSize);
      -
      12330  }
      -
      12331  break;
      -
      12332  default:
      -
      12333  VMA_ASSERT(0);
      -
      12334  }
      -
      12335 }
      -
      12336 #endif // #if VMA_STATS_STRING_ENABLED
      -
      12337 
      -
      12338 
      -
      12340 // class VmaDeviceMemoryBlock
      -
      12341 
      -
      12342 VmaDeviceMemoryBlock::VmaDeviceMemoryBlock(VmaAllocator hAllocator) :
      -
      12343  m_pMetadata(VMA_NULL),
      -
      12344  m_MemoryTypeIndex(UINT32_MAX),
      -
      12345  m_Id(0),
      -
      12346  m_hMemory(VK_NULL_HANDLE),
      -
      12347  m_MapCount(0),
      -
      12348  m_pMappedData(VMA_NULL)
      -
      12349 {
      -
      12350 }
      -
      12351 
      -
      12352 void VmaDeviceMemoryBlock::Init(
      -
      12353  VmaAllocator hAllocator,
      -
      12354  VmaPool hParentPool,
      -
      12355  uint32_t newMemoryTypeIndex,
      -
      12356  VkDeviceMemory newMemory,
      -
      12357  VkDeviceSize newSize,
      -
      12358  uint32_t id,
      -
      12359  uint32_t algorithm)
      -
      12360 {
      -
      12361  VMA_ASSERT(m_hMemory == VK_NULL_HANDLE);
      -
      12362 
      -
      12363  m_hParentPool = hParentPool;
      -
      12364  m_MemoryTypeIndex = newMemoryTypeIndex;
      -
      12365  m_Id = id;
      -
      12366  m_hMemory = newMemory;
      -
      12367 
      -
      12368  switch(algorithm)
      -
      12369  {
      - -
      12371  m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_Linear)(hAllocator);
      -
      12372  break;
      - -
      12374  m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_Buddy)(hAllocator);
      -
      12375  break;
      -
      12376  default:
      -
      12377  VMA_ASSERT(0);
      -
      12378  // Fall-through.
      -
      12379  case 0:
      -
      12380  m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_Generic)(hAllocator);
      -
      12381  }
      -
      12382  m_pMetadata->Init(newSize);
      -
      12383 }
      -
      12384 
      -
      12385 void VmaDeviceMemoryBlock::Destroy(VmaAllocator allocator)
      -
      12386 {
      -
      12387  // This is the most important assert in the entire library.
      -
      12388  // Hitting it means you have some memory leak - unreleased VmaAllocation objects.
      -
      12389  VMA_ASSERT(m_pMetadata->IsEmpty() && "Some allocations were not freed before destruction of this memory block!");
      -
      12390 
      -
      12391  VMA_ASSERT(m_hMemory != VK_NULL_HANDLE);
      -
      12392  allocator->FreeVulkanMemory(m_MemoryTypeIndex, m_pMetadata->GetSize(), m_hMemory);
      -
      12393  m_hMemory = VK_NULL_HANDLE;
      -
      12394 
      -
      12395  vma_delete(allocator, m_pMetadata);
      -
      12396  m_pMetadata = VMA_NULL;
      -
      12397 }
      -
      12398 
      -
      12399 bool VmaDeviceMemoryBlock::Validate() const
      -
      12400 {
      -
      12401  VMA_VALIDATE((m_hMemory != VK_NULL_HANDLE) &&
      -
      12402  (m_pMetadata->GetSize() != 0));
      -
      12403 
      -
      12404  return m_pMetadata->Validate();
      -
      12405 }
      -
      12406 
      -
      12407 VkResult VmaDeviceMemoryBlock::CheckCorruption(VmaAllocator hAllocator)
      -
      12408 {
      -
      12409  void* pData = nullptr;
      -
      12410  VkResult res = Map(hAllocator, 1, &pData);
      -
      12411  if(res != VK_SUCCESS)
      -
      12412  {
      -
      12413  return res;
      -
      12414  }
      -
      12415 
      -
      12416  res = m_pMetadata->CheckCorruption(pData);
      -
      12417 
      -
      12418  Unmap(hAllocator, 1);
      -
      12419 
      -
      12420  return res;
      -
      12421 }
      -
      12422 
      -
      12423 VkResult VmaDeviceMemoryBlock::Map(VmaAllocator hAllocator, uint32_t count, void** ppData)
      -
      12424 {
      -
      12425  if(count == 0)
      -
      12426  {
      -
      12427  return VK_SUCCESS;
      -
      12428  }
      -
      12429 
      -
      12430  VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex);
      -
      12431  if(m_MapCount != 0)
      -
      12432  {
      -
      12433  m_MapCount += count;
      -
      12434  VMA_ASSERT(m_pMappedData != VMA_NULL);
      -
      12435  if(ppData != VMA_NULL)
      -
      12436  {
      -
      12437  *ppData = m_pMappedData;
      -
      12438  }
      -
      12439  return VK_SUCCESS;
      -
      12440  }
      -
      12441  else
      -
      12442  {
      -
      12443  VkResult result = (*hAllocator->GetVulkanFunctions().vkMapMemory)(
      -
      12444  hAllocator->m_hDevice,
      -
      12445  m_hMemory,
      -
      12446  0, // offset
      -
      12447  VK_WHOLE_SIZE,
      -
      12448  0, // flags
      -
      12449  &m_pMappedData);
      -
      12450  if(result == VK_SUCCESS)
      -
      12451  {
      -
      12452  if(ppData != VMA_NULL)
      -
      12453  {
      -
      12454  *ppData = m_pMappedData;
      -
      12455  }
      -
      12456  m_MapCount = count;
      -
      12457  }
      -
      12458  return result;
      -
      12459  }
      -
      12460 }
      -
      12461 
      -
      12462 void VmaDeviceMemoryBlock::Unmap(VmaAllocator hAllocator, uint32_t count)
      -
      12463 {
      -
      12464  if(count == 0)
      -
      12465  {
      -
      12466  return;
      -
      12467  }
      -
      12468 
      -
      12469  VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex);
      -
      12470  if(m_MapCount >= count)
      -
      12471  {
      -
      12472  m_MapCount -= count;
      -
      12473  if(m_MapCount == 0)
      -
      12474  {
      -
      12475  m_pMappedData = VMA_NULL;
      -
      12476  (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(hAllocator->m_hDevice, m_hMemory);
      -
      12477  }
      -
      12478  }
      -
      12479  else
      -
      12480  {
      -
      12481  VMA_ASSERT(0 && "VkDeviceMemory block is being unmapped while it was not previously mapped.");
      -
      12482  }
      -
      12483 }
      -
      12484 
      -
      12485 VkResult VmaDeviceMemoryBlock::WriteMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize)
      -
      12486 {
      -
      12487  VMA_ASSERT(VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_MARGIN % 4 == 0 && VMA_DEBUG_DETECT_CORRUPTION);
      -
      12488  VMA_ASSERT(allocOffset >= VMA_DEBUG_MARGIN);
      -
      12489 
      -
      12490  void* pData;
      -
      12491  VkResult res = Map(hAllocator, 1, &pData);
      -
      12492  if(res != VK_SUCCESS)
      -
      12493  {
      -
      12494  return res;
      -
      12495  }
      -
      12496 
      -
      12497  VmaWriteMagicValue(pData, allocOffset - VMA_DEBUG_MARGIN);
      -
      12498  VmaWriteMagicValue(pData, allocOffset + allocSize);
      -
      12499 
      -
      12500  Unmap(hAllocator, 1);
      -
      12501 
      -
      12502  return VK_SUCCESS;
      -
      12503 }
      -
      12504 
      -
      12505 VkResult VmaDeviceMemoryBlock::ValidateMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize)
      -
      12506 {
      -
      12507  VMA_ASSERT(VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_MARGIN % 4 == 0 && VMA_DEBUG_DETECT_CORRUPTION);
      -
      12508  VMA_ASSERT(allocOffset >= VMA_DEBUG_MARGIN);
      -
      12509 
      -
      12510  void* pData;
      -
      12511  VkResult res = Map(hAllocator, 1, &pData);
      -
      12512  if(res != VK_SUCCESS)
      -
      12513  {
      -
      12514  return res;
      -
      12515  }
      +
      12256 void VmaBlockMetadata_Buddy::Alloc(
      +
      12257  const VmaAllocationRequest& request,
      +
      12258  VmaSuballocationType type,
      +
      12259  VkDeviceSize allocSize,
      +
      12260  VmaAllocation hAllocation)
      +
      12261 {
      +
      12262  VMA_ASSERT(request.type == VmaAllocationRequestType::Normal);
      +
      12263 
      +
      12264  const uint32_t targetLevel = AllocSizeToLevel(allocSize);
      +
      12265  uint32_t currLevel = (uint32_t)(uintptr_t)request.customData;
      +
      12266 
      +
      12267  Node* currNode = m_FreeList[currLevel].front;
      +
      12268  VMA_ASSERT(currNode != VMA_NULL && currNode->type == Node::TYPE_FREE);
      +
      12269  while(currNode->offset != request.offset)
      +
      12270  {
      +
      12271  currNode = currNode->free.next;
      +
      12272  VMA_ASSERT(currNode != VMA_NULL && currNode->type == Node::TYPE_FREE);
      +
      12273  }
      +
      12274 
      +
      12275  // Go down, splitting free nodes.
      +
      12276  while(currLevel < targetLevel)
      +
      12277  {
      +
      12278  // currNode is already first free node at currLevel.
      +
      12279  // Remove it from list of free nodes at this currLevel.
      +
      12280  RemoveFromFreeList(currLevel, currNode);
      +
      12281 
      +
      12282  const uint32_t childrenLevel = currLevel + 1;
      +
      12283 
      +
      12284  // Create two free sub-nodes.
      +
      12285  Node* leftChild = vma_new(GetAllocationCallbacks(), Node)();
      +
      12286  Node* rightChild = vma_new(GetAllocationCallbacks(), Node)();
      +
      12287 
      +
      12288  leftChild->offset = currNode->offset;
      +
      12289  leftChild->type = Node::TYPE_FREE;
      +
      12290  leftChild->parent = currNode;
      +
      12291  leftChild->buddy = rightChild;
      +
      12292 
      +
      12293  rightChild->offset = currNode->offset + LevelToNodeSize(childrenLevel);
      +
      12294  rightChild->type = Node::TYPE_FREE;
      +
      12295  rightChild->parent = currNode;
      +
      12296  rightChild->buddy = leftChild;
      +
      12297 
      +
      12298  // Convert current currNode to split type.
      +
      12299  currNode->type = Node::TYPE_SPLIT;
      +
      12300  currNode->split.leftChild = leftChild;
      +
      12301 
      +
      12302  // Add child nodes to free list. Order is important!
      +
      12303  AddToFreeListFront(childrenLevel, rightChild);
      +
      12304  AddToFreeListFront(childrenLevel, leftChild);
      +
      12305 
      +
      12306  ++m_FreeCount;
      +
      12307  //m_SumFreeSize -= LevelToNodeSize(currLevel) % 2; // Useful only when level node sizes can be non power of 2.
      +
      12308  ++currLevel;
      +
      12309  currNode = m_FreeList[currLevel].front;
      +
      12310 
      +
      12311  /*
      +
      12312  We can be sure that currNode, as left child of node previously split,
      +
      12313  also fullfills the alignment requirement.
      +
      12314  */
      +
      12315  }
      +
      12316 
      +
      12317  // Remove from free list.
      +
      12318  VMA_ASSERT(currLevel == targetLevel &&
      +
      12319  currNode != VMA_NULL &&
      +
      12320  currNode->type == Node::TYPE_FREE);
      +
      12321  RemoveFromFreeList(currLevel, currNode);
      +
      12322 
      +
      12323  // Convert to allocation node.
      +
      12324  currNode->type = Node::TYPE_ALLOCATION;
      +
      12325  currNode->allocation.alloc = hAllocation;
      +
      12326 
      +
      12327  ++m_AllocationCount;
      +
      12328  --m_FreeCount;
      +
      12329  m_SumFreeSize -= allocSize;
      +
      12330 }
      +
      12331 
      +
      12332 void VmaBlockMetadata_Buddy::DeleteNode(Node* node)
      +
      12333 {
      +
      12334  if(node->type == Node::TYPE_SPLIT)
      +
      12335  {
      +
      12336  DeleteNode(node->split.leftChild->buddy);
      +
      12337  DeleteNode(node->split.leftChild);
      +
      12338  }
      +
      12339 
      +
      12340  vma_delete(GetAllocationCallbacks(), node);
      +
      12341 }
      +
      12342 
      +
      12343 bool VmaBlockMetadata_Buddy::ValidateNode(ValidationContext& ctx, const Node* parent, const Node* curr, uint32_t level, VkDeviceSize levelNodeSize) const
      +
      12344 {
      +
      12345  VMA_VALIDATE(level < m_LevelCount);
      +
      12346  VMA_VALIDATE(curr->parent == parent);
      +
      12347  VMA_VALIDATE((curr->buddy == VMA_NULL) == (parent == VMA_NULL));
      +
      12348  VMA_VALIDATE(curr->buddy == VMA_NULL || curr->buddy->buddy == curr);
      +
      12349  switch(curr->type)
      +
      12350  {
      +
      12351  case Node::TYPE_FREE:
      +
      12352  // curr->free.prev, next are validated separately.
      +
      12353  ctx.calculatedSumFreeSize += levelNodeSize;
      +
      12354  ++ctx.calculatedFreeCount;
      +
      12355  break;
      +
      12356  case Node::TYPE_ALLOCATION:
      +
      12357  ++ctx.calculatedAllocationCount;
      +
      12358  ctx.calculatedSumFreeSize += levelNodeSize - curr->allocation.alloc->GetSize();
      +
      12359  VMA_VALIDATE(curr->allocation.alloc != VK_NULL_HANDLE);
      +
      12360  break;
      +
      12361  case Node::TYPE_SPLIT:
      +
      12362  {
      +
      12363  const uint32_t childrenLevel = level + 1;
      +
      12364  const VkDeviceSize childrenLevelNodeSize = levelNodeSize / 2;
      +
      12365  const Node* const leftChild = curr->split.leftChild;
      +
      12366  VMA_VALIDATE(leftChild != VMA_NULL);
      +
      12367  VMA_VALIDATE(leftChild->offset == curr->offset);
      +
      12368  if(!ValidateNode(ctx, curr, leftChild, childrenLevel, childrenLevelNodeSize))
      +
      12369  {
      +
      12370  VMA_VALIDATE(false && "ValidateNode for left child failed.");
      +
      12371  }
      +
      12372  const Node* const rightChild = leftChild->buddy;
      +
      12373  VMA_VALIDATE(rightChild->offset == curr->offset + childrenLevelNodeSize);
      +
      12374  if(!ValidateNode(ctx, curr, rightChild, childrenLevel, childrenLevelNodeSize))
      +
      12375  {
      +
      12376  VMA_VALIDATE(false && "ValidateNode for right child failed.");
      +
      12377  }
      +
      12378  }
      +
      12379  break;
      +
      12380  default:
      +
      12381  return false;
      +
      12382  }
      +
      12383 
      +
      12384  return true;
      +
      12385 }
      +
      12386 
      +
      12387 uint32_t VmaBlockMetadata_Buddy::AllocSizeToLevel(VkDeviceSize allocSize) const
      +
      12388 {
      +
      12389  // I know this could be optimized somehow e.g. by using std::log2p1 from C++20.
      +
      12390  uint32_t level = 0;
      +
      12391  VkDeviceSize currLevelNodeSize = m_UsableSize;
      +
      12392  VkDeviceSize nextLevelNodeSize = currLevelNodeSize >> 1;
      +
      12393  while(allocSize <= nextLevelNodeSize && level + 1 < m_LevelCount)
      +
      12394  {
      +
      12395  ++level;
      +
      12396  currLevelNodeSize = nextLevelNodeSize;
      +
      12397  nextLevelNodeSize = currLevelNodeSize >> 1;
      +
      12398  }
      +
      12399  return level;
      +
      12400 }
      +
      12401 
      +
      12402 void VmaBlockMetadata_Buddy::FreeAtOffset(VmaAllocation alloc, VkDeviceSize offset)
      +
      12403 {
      +
      12404  // Find node and level.
      +
      12405  Node* node = m_Root;
      +
      12406  VkDeviceSize nodeOffset = 0;
      +
      12407  uint32_t level = 0;
      +
      12408  VkDeviceSize levelNodeSize = LevelToNodeSize(0);
      +
      12409  while(node->type == Node::TYPE_SPLIT)
      +
      12410  {
      +
      12411  const VkDeviceSize nextLevelSize = levelNodeSize >> 1;
      +
      12412  if(offset < nodeOffset + nextLevelSize)
      +
      12413  {
      +
      12414  node = node->split.leftChild;
      +
      12415  }
      +
      12416  else
      +
      12417  {
      +
      12418  node = node->split.leftChild->buddy;
      +
      12419  nodeOffset += nextLevelSize;
      +
      12420  }
      +
      12421  ++level;
      +
      12422  levelNodeSize = nextLevelSize;
      +
      12423  }
      +
      12424 
      +
      12425  VMA_ASSERT(node != VMA_NULL && node->type == Node::TYPE_ALLOCATION);
      +
      12426  VMA_ASSERT(alloc == VK_NULL_HANDLE || node->allocation.alloc == alloc);
      +
      12427 
      +
      12428  ++m_FreeCount;
      +
      12429  --m_AllocationCount;
      +
      12430  m_SumFreeSize += alloc->GetSize();
      +
      12431 
      +
      12432  node->type = Node::TYPE_FREE;
      +
      12433 
      +
      12434  // Join free nodes if possible.
      +
      12435  while(level > 0 && node->buddy->type == Node::TYPE_FREE)
      +
      12436  {
      +
      12437  RemoveFromFreeList(level, node->buddy);
      +
      12438  Node* const parent = node->parent;
      +
      12439 
      +
      12440  vma_delete(GetAllocationCallbacks(), node->buddy);
      +
      12441  vma_delete(GetAllocationCallbacks(), node);
      +
      12442  parent->type = Node::TYPE_FREE;
      +
      12443 
      +
      12444  node = parent;
      +
      12445  --level;
      +
      12446  //m_SumFreeSize += LevelToNodeSize(level) % 2; // Useful only when level node sizes can be non power of 2.
      +
      12447  --m_FreeCount;
      +
      12448  }
      +
      12449 
      +
      12450  AddToFreeListFront(level, node);
      +
      12451 }
      +
      12452 
      +
      12453 void VmaBlockMetadata_Buddy::CalcAllocationStatInfoNode(VmaStatInfo& outInfo, const Node* node, VkDeviceSize levelNodeSize) const
      +
      12454 {
      +
      12455  switch(node->type)
      +
      12456  {
      +
      12457  case Node::TYPE_FREE:
      +
      12458  ++outInfo.unusedRangeCount;
      +
      12459  outInfo.unusedBytes += levelNodeSize;
      +
      12460  outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, levelNodeSize);
      +
      12461  outInfo.unusedRangeSizeMin = VMA_MAX(outInfo.unusedRangeSizeMin, levelNodeSize);
      +
      12462  break;
      +
      12463  case Node::TYPE_ALLOCATION:
      +
      12464  {
      +
      12465  const VkDeviceSize allocSize = node->allocation.alloc->GetSize();
      +
      12466  ++outInfo.allocationCount;
      +
      12467  outInfo.usedBytes += allocSize;
      +
      12468  outInfo.allocationSizeMax = VMA_MAX(outInfo.allocationSizeMax, allocSize);
      +
      12469  outInfo.allocationSizeMin = VMA_MAX(outInfo.allocationSizeMin, allocSize);
      +
      12470 
      +
      12471  const VkDeviceSize unusedRangeSize = levelNodeSize - allocSize;
      +
      12472  if(unusedRangeSize > 0)
      +
      12473  {
      +
      12474  ++outInfo.unusedRangeCount;
      +
      12475  outInfo.unusedBytes += unusedRangeSize;
      +
      12476  outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, unusedRangeSize);
      +
      12477  outInfo.unusedRangeSizeMin = VMA_MAX(outInfo.unusedRangeSizeMin, unusedRangeSize);
      +
      12478  }
      +
      12479  }
      +
      12480  break;
      +
      12481  case Node::TYPE_SPLIT:
      +
      12482  {
      +
      12483  const VkDeviceSize childrenNodeSize = levelNodeSize / 2;
      +
      12484  const Node* const leftChild = node->split.leftChild;
      +
      12485  CalcAllocationStatInfoNode(outInfo, leftChild, childrenNodeSize);
      +
      12486  const Node* const rightChild = leftChild->buddy;
      +
      12487  CalcAllocationStatInfoNode(outInfo, rightChild, childrenNodeSize);
      +
      12488  }
      +
      12489  break;
      +
      12490  default:
      +
      12491  VMA_ASSERT(0);
      +
      12492  }
      +
      12493 }
      +
      12494 
      +
      12495 void VmaBlockMetadata_Buddy::AddToFreeListFront(uint32_t level, Node* node)
      +
      12496 {
      +
      12497  VMA_ASSERT(node->type == Node::TYPE_FREE);
      +
      12498 
      +
      12499  // List is empty.
      +
      12500  Node* const frontNode = m_FreeList[level].front;
      +
      12501  if(frontNode == VMA_NULL)
      +
      12502  {
      +
      12503  VMA_ASSERT(m_FreeList[level].back == VMA_NULL);
      +
      12504  node->free.prev = node->free.next = VMA_NULL;
      +
      12505  m_FreeList[level].front = m_FreeList[level].back = node;
      +
      12506  }
      +
      12507  else
      +
      12508  {
      +
      12509  VMA_ASSERT(frontNode->free.prev == VMA_NULL);
      +
      12510  node->free.prev = VMA_NULL;
      +
      12511  node->free.next = frontNode;
      +
      12512  frontNode->free.prev = node;
      +
      12513  m_FreeList[level].front = node;
      +
      12514  }
      +
      12515 }
      12516 
      -
      12517  if(!VmaValidateMagicValue(pData, allocOffset - VMA_DEBUG_MARGIN))
      -
      12518  {
      -
      12519  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED BEFORE FREED ALLOCATION!");
      -
      12520  }
      -
      12521  else if(!VmaValidateMagicValue(pData, allocOffset + allocSize))
      -
      12522  {
      -
      12523  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER FREED ALLOCATION!");
      -
      12524  }
      -
      12525 
      -
      12526  Unmap(hAllocator, 1);
      -
      12527 
      -
      12528  return VK_SUCCESS;
      -
      12529 }
      -
      12530 
      -
      12531 VkResult VmaDeviceMemoryBlock::BindBufferMemory(
      -
      12532  const VmaAllocator hAllocator,
      -
      12533  const VmaAllocation hAllocation,
      -
      12534  VkDeviceSize allocationLocalOffset,
      -
      12535  VkBuffer hBuffer,
      -
      12536  const void* pNext)
      -
      12537 {
      -
      12538  VMA_ASSERT(hAllocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK &&
      -
      12539  hAllocation->GetBlock() == this);
      -
      12540  VMA_ASSERT(allocationLocalOffset < hAllocation->GetSize() &&
      -
      12541  "Invalid allocationLocalOffset. Did you forget that this offset is relative to the beginning of the allocation, not the whole memory block?");
      -
      12542  const VkDeviceSize memoryOffset = hAllocation->GetOffset() + allocationLocalOffset;
      -
      12543  // This lock is important so that we don't call vkBind... and/or vkMap... simultaneously on the same VkDeviceMemory from multiple threads.
      -
      12544  VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex);
      -
      12545  return hAllocator->BindVulkanBuffer(m_hMemory, memoryOffset, hBuffer, pNext);
      +
      12517 void VmaBlockMetadata_Buddy::RemoveFromFreeList(uint32_t level, Node* node)
      +
      12518 {
      +
      12519  VMA_ASSERT(m_FreeList[level].front != VMA_NULL);
      +
      12520 
      +
      12521  // It is at the front.
      +
      12522  if(node->free.prev == VMA_NULL)
      +
      12523  {
      +
      12524  VMA_ASSERT(m_FreeList[level].front == node);
      +
      12525  m_FreeList[level].front = node->free.next;
      +
      12526  }
      +
      12527  else
      +
      12528  {
      +
      12529  Node* const prevFreeNode = node->free.prev;
      +
      12530  VMA_ASSERT(prevFreeNode->free.next == node);
      +
      12531  prevFreeNode->free.next = node->free.next;
      +
      12532  }
      +
      12533 
      +
      12534  // It is at the back.
      +
      12535  if(node->free.next == VMA_NULL)
      +
      12536  {
      +
      12537  VMA_ASSERT(m_FreeList[level].back == node);
      +
      12538  m_FreeList[level].back = node->free.prev;
      +
      12539  }
      +
      12540  else
      +
      12541  {
      +
      12542  Node* const nextFreeNode = node->free.next;
      +
      12543  VMA_ASSERT(nextFreeNode->free.prev == node);
      +
      12544  nextFreeNode->free.prev = node->free.prev;
      +
      12545  }
      12546 }
      12547 
      -
      12548 VkResult VmaDeviceMemoryBlock::BindImageMemory(
      -
      12549  const VmaAllocator hAllocator,
      -
      12550  const VmaAllocation hAllocation,
      -
      12551  VkDeviceSize allocationLocalOffset,
      -
      12552  VkImage hImage,
      -
      12553  const void* pNext)
      -
      12554 {
      -
      12555  VMA_ASSERT(hAllocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK &&
      -
      12556  hAllocation->GetBlock() == this);
      -
      12557  VMA_ASSERT(allocationLocalOffset < hAllocation->GetSize() &&
      -
      12558  "Invalid allocationLocalOffset. Did you forget that this offset is relative to the beginning of the allocation, not the whole memory block?");
      -
      12559  const VkDeviceSize memoryOffset = hAllocation->GetOffset() + allocationLocalOffset;
      -
      12560  // This lock is important so that we don't call vkBind... and/or vkMap... simultaneously on the same VkDeviceMemory from multiple threads.
      -
      12561  VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex);
      -
      12562  return hAllocator->BindVulkanImage(m_hMemory, memoryOffset, hImage, pNext);
      -
      12563 }
      -
      12564 
      -
      12565 static void InitStatInfo(VmaStatInfo& outInfo)
      -
      12566 {
      -
      12567  memset(&outInfo, 0, sizeof(outInfo));
      -
      12568  outInfo.allocationSizeMin = UINT64_MAX;
      -
      12569  outInfo.unusedRangeSizeMin = UINT64_MAX;
      -
      12570 }
      -
      12571 
      -
      12572 // Adds statistics srcInfo into inoutInfo, like: inoutInfo += srcInfo.
      -
      12573 static void VmaAddStatInfo(VmaStatInfo& inoutInfo, const VmaStatInfo& srcInfo)
      -
      12574 {
      -
      12575  inoutInfo.blockCount += srcInfo.blockCount;
      -
      12576  inoutInfo.allocationCount += srcInfo.allocationCount;
      -
      12577  inoutInfo.unusedRangeCount += srcInfo.unusedRangeCount;
      -
      12578  inoutInfo.usedBytes += srcInfo.usedBytes;
      -
      12579  inoutInfo.unusedBytes += srcInfo.unusedBytes;
      -
      12580  inoutInfo.allocationSizeMin = VMA_MIN(inoutInfo.allocationSizeMin, srcInfo.allocationSizeMin);
      -
      12581  inoutInfo.allocationSizeMax = VMA_MAX(inoutInfo.allocationSizeMax, srcInfo.allocationSizeMax);
      -
      12582  inoutInfo.unusedRangeSizeMin = VMA_MIN(inoutInfo.unusedRangeSizeMin, srcInfo.unusedRangeSizeMin);
      -
      12583  inoutInfo.unusedRangeSizeMax = VMA_MAX(inoutInfo.unusedRangeSizeMax, srcInfo.unusedRangeSizeMax);
      -
      12584 }
      -
      12585 
      -
      12586 static void VmaPostprocessCalcStatInfo(VmaStatInfo& inoutInfo)
      -
      12587 {
      -
      12588  inoutInfo.allocationSizeAvg = (inoutInfo.allocationCount > 0) ?
      -
      12589  VmaRoundDiv<VkDeviceSize>(inoutInfo.usedBytes, inoutInfo.allocationCount) : 0;
      -
      12590  inoutInfo.unusedRangeSizeAvg = (inoutInfo.unusedRangeCount > 0) ?
      -
      12591  VmaRoundDiv<VkDeviceSize>(inoutInfo.unusedBytes, inoutInfo.unusedRangeCount) : 0;
      -
      12592 }
      -
      12593 
      -
      12594 VmaPool_T::VmaPool_T(
      -
      12595  VmaAllocator hAllocator,
      -
      12596  const VmaPoolCreateInfo& createInfo,
      -
      12597  VkDeviceSize preferredBlockSize) :
      -
      12598  m_BlockVector(
      -
      12599  hAllocator,
      -
      12600  this, // hParentPool
      -
      12601  createInfo.memoryTypeIndex,
      -
      12602  createInfo.blockSize != 0 ? createInfo.blockSize : preferredBlockSize,
      -
      12603  createInfo.minBlockCount,
      -
      12604  createInfo.maxBlockCount,
      -
      12605  (createInfo.flags & VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT) != 0 ? 1 : hAllocator->GetBufferImageGranularity(),
      -
      12606  createInfo.frameInUseCount,
      -
      12607  createInfo.blockSize != 0, // explicitBlockSize
      -
      12608  createInfo.flags & VMA_POOL_CREATE_ALGORITHM_MASK,
      -
      12609  createInfo.priority), // algorithm
      -
      12610  m_Id(0),
      -
      12611  m_Name(VMA_NULL)
      -
      12612 {
      -
      12613 }
      -
      12614 
      -
      12615 VmaPool_T::~VmaPool_T()
      -
      12616 {
      -
      12617 }
      -
      12618 
      -
      12619 void VmaPool_T::SetName(const char* pName)
      -
      12620 {
      -
      12621  const VkAllocationCallbacks* allocs = m_BlockVector.GetAllocator()->GetAllocationCallbacks();
      -
      12622  VmaFreeString(allocs, m_Name);
      -
      12623 
      -
      12624  if(pName != VMA_NULL)
      -
      12625  {
      -
      12626  m_Name = VmaCreateStringCopy(allocs, pName);
      -
      12627  }
      -
      12628  else
      -
      12629  {
      -
      12630  m_Name = VMA_NULL;
      -
      12631  }
      -
      12632 }
      +
      12548 #if VMA_STATS_STRING_ENABLED
      +
      12549 void VmaBlockMetadata_Buddy::PrintDetailedMapNode(class VmaJsonWriter& json, const Node* node, VkDeviceSize levelNodeSize) const
      +
      12550 {
      +
      12551  switch(node->type)
      +
      12552  {
      +
      12553  case Node::TYPE_FREE:
      +
      12554  PrintDetailedMap_UnusedRange(json, node->offset, levelNodeSize);
      +
      12555  break;
      +
      12556  case Node::TYPE_ALLOCATION:
      +
      12557  {
      +
      12558  PrintDetailedMap_Allocation(json, node->offset, node->allocation.alloc);
      +
      12559  const VkDeviceSize allocSize = node->allocation.alloc->GetSize();
      +
      12560  if(allocSize < levelNodeSize)
      +
      12561  {
      +
      12562  PrintDetailedMap_UnusedRange(json, node->offset + allocSize, levelNodeSize - allocSize);
      +
      12563  }
      +
      12564  }
      +
      12565  break;
      +
      12566  case Node::TYPE_SPLIT:
      +
      12567  {
      +
      12568  const VkDeviceSize childrenNodeSize = levelNodeSize / 2;
      +
      12569  const Node* const leftChild = node->split.leftChild;
      +
      12570  PrintDetailedMapNode(json, leftChild, childrenNodeSize);
      +
      12571  const Node* const rightChild = leftChild->buddy;
      +
      12572  PrintDetailedMapNode(json, rightChild, childrenNodeSize);
      +
      12573  }
      +
      12574  break;
      +
      12575  default:
      +
      12576  VMA_ASSERT(0);
      +
      12577  }
      +
      12578 }
      +
      12579 #endif // #if VMA_STATS_STRING_ENABLED
      +
      12580 
      +
      12581 
      +
      12583 // class VmaDeviceMemoryBlock
      +
      12584 
      +
      12585 VmaDeviceMemoryBlock::VmaDeviceMemoryBlock(VmaAllocator hAllocator) :
      +
      12586  m_pMetadata(VMA_NULL),
      +
      12587  m_MemoryTypeIndex(UINT32_MAX),
      +
      12588  m_Id(0),
      +
      12589  m_hMemory(VK_NULL_HANDLE),
      +
      12590  m_MapCount(0),
      +
      12591  m_pMappedData(VMA_NULL)
      +
      12592 {
      +
      12593 }
      +
      12594 
      +
      12595 void VmaDeviceMemoryBlock::Init(
      +
      12596  VmaAllocator hAllocator,
      +
      12597  VmaPool hParentPool,
      +
      12598  uint32_t newMemoryTypeIndex,
      +
      12599  VkDeviceMemory newMemory,
      +
      12600  VkDeviceSize newSize,
      +
      12601  uint32_t id,
      +
      12602  uint32_t algorithm)
      +
      12603 {
      +
      12604  VMA_ASSERT(m_hMemory == VK_NULL_HANDLE);
      +
      12605 
      +
      12606  m_hParentPool = hParentPool;
      +
      12607  m_MemoryTypeIndex = newMemoryTypeIndex;
      +
      12608  m_Id = id;
      +
      12609  m_hMemory = newMemory;
      +
      12610 
      +
      12611  switch(algorithm)
      +
      12612  {
      + +
      12614  m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_Linear)(hAllocator);
      +
      12615  break;
      + +
      12617  m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_Buddy)(hAllocator);
      +
      12618  break;
      +
      12619  default:
      +
      12620  VMA_ASSERT(0);
      +
      12621  // Fall-through.
      +
      12622  case 0:
      +
      12623  m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_Generic)(hAllocator);
      +
      12624  }
      +
      12625  m_pMetadata->Init(newSize);
      +
      12626 }
      +
      12627 
      +
      12628 void VmaDeviceMemoryBlock::Destroy(VmaAllocator allocator)
      +
      12629 {
      +
      12630  // This is the most important assert in the entire library.
      +
      12631  // Hitting it means you have some memory leak - unreleased VmaAllocation objects.
      +
      12632  VMA_ASSERT(m_pMetadata->IsEmpty() && "Some allocations were not freed before destruction of this memory block!");
      12633 
      -
      12634 #if VMA_STATS_STRING_ENABLED
      -
      12635 
      -
      12636 #endif // #if VMA_STATS_STRING_ENABLED
      +
      12634  VMA_ASSERT(m_hMemory != VK_NULL_HANDLE);
      +
      12635  allocator->FreeVulkanMemory(m_MemoryTypeIndex, m_pMetadata->GetSize(), m_hMemory);
      +
      12636  m_hMemory = VK_NULL_HANDLE;
      12637 
      -
      12638 VmaBlockVector::VmaBlockVector(
      -
      12639  VmaAllocator hAllocator,
      -
      12640  VmaPool hParentPool,
      -
      12641  uint32_t memoryTypeIndex,
      -
      12642  VkDeviceSize preferredBlockSize,
      -
      12643  size_t minBlockCount,
      -
      12644  size_t maxBlockCount,
      -
      12645  VkDeviceSize bufferImageGranularity,
      -
      12646  uint32_t frameInUseCount,
      -
      12647  bool explicitBlockSize,
      -
      12648  uint32_t algorithm,
      -
      12649  float priority) :
      -
      12650  m_hAllocator(hAllocator),
      -
      12651  m_hParentPool(hParentPool),
      -
      12652  m_MemoryTypeIndex(memoryTypeIndex),
      -
      12653  m_PreferredBlockSize(preferredBlockSize),
      -
      12654  m_MinBlockCount(minBlockCount),
      -
      12655  m_MaxBlockCount(maxBlockCount),
      -
      12656  m_BufferImageGranularity(bufferImageGranularity),
      -
      12657  m_FrameInUseCount(frameInUseCount),
      -
      12658  m_ExplicitBlockSize(explicitBlockSize),
      -
      12659  m_Algorithm(algorithm),
      -
      12660  m_Priority(priority),
      -
      12661  m_HasEmptyBlock(false),
      -
      12662  m_Blocks(VmaStlAllocator<VmaDeviceMemoryBlock*>(hAllocator->GetAllocationCallbacks())),
      -
      12663  m_NextBlockId(0)
      -
      12664 {
      -
      12665 }
      -
      12666 
      -
      12667 VmaBlockVector::~VmaBlockVector()
      -
      12668 {
      -
      12669  for(size_t i = m_Blocks.size(); i--; )
      -
      12670  {
      -
      12671  m_Blocks[i]->Destroy(m_hAllocator);
      -
      12672  vma_delete(m_hAllocator, m_Blocks[i]);
      -
      12673  }
      -
      12674 }
      -
      12675 
      -
      12676 VkResult VmaBlockVector::CreateMinBlocks()
      -
      12677 {
      -
      12678  for(size_t i = 0; i < m_MinBlockCount; ++i)
      -
      12679  {
      -
      12680  VkResult res = CreateBlock(m_PreferredBlockSize, VMA_NULL);
      -
      12681  if(res != VK_SUCCESS)
      -
      12682  {
      -
      12683  return res;
      -
      12684  }
      -
      12685  }
      -
      12686  return VK_SUCCESS;
      -
      12687 }
      -
      12688 
      -
      12689 void VmaBlockVector::GetPoolStats(VmaPoolStats* pStats)
      -
      12690 {
      -
      12691  VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex);
      -
      12692 
      -
      12693  const size_t blockCount = m_Blocks.size();
      -
      12694 
      -
      12695  pStats->size = 0;
      -
      12696  pStats->unusedSize = 0;
      -
      12697  pStats->allocationCount = 0;
      -
      12698  pStats->unusedRangeCount = 0;
      -
      12699  pStats->unusedRangeSizeMax = 0;
      -
      12700  pStats->blockCount = blockCount;
      -
      12701 
      -
      12702  for(uint32_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
      -
      12703  {
      -
      12704  const VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex];
      -
      12705  VMA_ASSERT(pBlock);
      -
      12706  VMA_HEAVY_ASSERT(pBlock->Validate());
      -
      12707  pBlock->m_pMetadata->AddPoolStats(*pStats);
      -
      12708  }
      -
      12709 }
      -
      12710 
      -
      12711 bool VmaBlockVector::IsEmpty()
      -
      12712 {
      -
      12713  VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex);
      -
      12714  return m_Blocks.empty();
      -
      12715 }
      -
      12716 
      -
      12717 bool VmaBlockVector::IsCorruptionDetectionEnabled() const
      -
      12718 {
      -
      12719  const uint32_t requiredMemFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
      -
      12720  return (VMA_DEBUG_DETECT_CORRUPTION != 0) &&
      -
      12721  (VMA_DEBUG_MARGIN > 0) &&
      -
      12722  (m_Algorithm == 0 || m_Algorithm == VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT) &&
      -
      12723  (m_hAllocator->m_MemProps.memoryTypes[m_MemoryTypeIndex].propertyFlags & requiredMemFlags) == requiredMemFlags;
      -
      12724 }
      -
      12725 
      -
      12726 static const uint32_t VMA_ALLOCATION_TRY_COUNT = 32;
      +
      12638  vma_delete(allocator, m_pMetadata);
      +
      12639  m_pMetadata = VMA_NULL;
      +
      12640 }
      +
      12641 
      +
      12642 bool VmaDeviceMemoryBlock::Validate() const
      +
      12643 {
      +
      12644  VMA_VALIDATE((m_hMemory != VK_NULL_HANDLE) &&
      +
      12645  (m_pMetadata->GetSize() != 0));
      +
      12646 
      +
      12647  return m_pMetadata->Validate();
      +
      12648 }
      +
      12649 
      +
      12650 VkResult VmaDeviceMemoryBlock::CheckCorruption(VmaAllocator hAllocator)
      +
      12651 {
      +
      12652  void* pData = nullptr;
      +
      12653  VkResult res = Map(hAllocator, 1, &pData);
      +
      12654  if(res != VK_SUCCESS)
      +
      12655  {
      +
      12656  return res;
      +
      12657  }
      +
      12658 
      +
      12659  res = m_pMetadata->CheckCorruption(pData);
      +
      12660 
      +
      12661  Unmap(hAllocator, 1);
      +
      12662 
      +
      12663  return res;
      +
      12664 }
      +
      12665 
      +
      12666 VkResult VmaDeviceMemoryBlock::Map(VmaAllocator hAllocator, uint32_t count, void** ppData)
      +
      12667 {
      +
      12668  if(count == 0)
      +
      12669  {
      +
      12670  return VK_SUCCESS;
      +
      12671  }
      +
      12672 
      +
      12673  VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex);
      +
      12674  if(m_MapCount != 0)
      +
      12675  {
      +
      12676  m_MapCount += count;
      +
      12677  VMA_ASSERT(m_pMappedData != VMA_NULL);
      +
      12678  if(ppData != VMA_NULL)
      +
      12679  {
      +
      12680  *ppData = m_pMappedData;
      +
      12681  }
      +
      12682  return VK_SUCCESS;
      +
      12683  }
      +
      12684  else
      +
      12685  {
      +
      12686  VkResult result = (*hAllocator->GetVulkanFunctions().vkMapMemory)(
      +
      12687  hAllocator->m_hDevice,
      +
      12688  m_hMemory,
      +
      12689  0, // offset
      +
      12690  VK_WHOLE_SIZE,
      +
      12691  0, // flags
      +
      12692  &m_pMappedData);
      +
      12693  if(result == VK_SUCCESS)
      +
      12694  {
      +
      12695  if(ppData != VMA_NULL)
      +
      12696  {
      +
      12697  *ppData = m_pMappedData;
      +
      12698  }
      +
      12699  m_MapCount = count;
      +
      12700  }
      +
      12701  return result;
      +
      12702  }
      +
      12703 }
      +
      12704 
      +
      12705 void VmaDeviceMemoryBlock::Unmap(VmaAllocator hAllocator, uint32_t count)
      +
      12706 {
      +
      12707  if(count == 0)
      +
      12708  {
      +
      12709  return;
      +
      12710  }
      +
      12711 
      +
      12712  VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex);
      +
      12713  if(m_MapCount >= count)
      +
      12714  {
      +
      12715  m_MapCount -= count;
      +
      12716  if(m_MapCount == 0)
      +
      12717  {
      +
      12718  m_pMappedData = VMA_NULL;
      +
      12719  (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(hAllocator->m_hDevice, m_hMemory);
      +
      12720  }
      +
      12721  }
      +
      12722  else
      +
      12723  {
      +
      12724  VMA_ASSERT(0 && "VkDeviceMemory block is being unmapped while it was not previously mapped.");
      +
      12725  }
      +
      12726 }
      12727 
      -
      12728 VkResult VmaBlockVector::Allocate(
      -
      12729  uint32_t currentFrameIndex,
      -
      12730  VkDeviceSize size,
      -
      12731  VkDeviceSize alignment,
      -
      12732  const VmaAllocationCreateInfo& createInfo,
      -
      12733  VmaSuballocationType suballocType,
      -
      12734  size_t allocationCount,
      -
      12735  VmaAllocation* pAllocations)
      -
      12736 {
      -
      12737  size_t allocIndex;
      -
      12738  VkResult res = VK_SUCCESS;
      +
      12728 VkResult VmaDeviceMemoryBlock::WriteMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize)
      +
      12729 {
      +
      12730  VMA_ASSERT(VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_MARGIN % 4 == 0 && VMA_DEBUG_DETECT_CORRUPTION);
      +
      12731  VMA_ASSERT(allocOffset >= VMA_DEBUG_MARGIN);
      +
      12732 
      +
      12733  void* pData;
      +
      12734  VkResult res = Map(hAllocator, 1, &pData);
      +
      12735  if(res != VK_SUCCESS)
      +
      12736  {
      +
      12737  return res;
      +
      12738  }
      12739 
      -
      12740  if(IsCorruptionDetectionEnabled())
      -
      12741  {
      -
      12742  size = VmaAlignUp<VkDeviceSize>(size, sizeof(VMA_CORRUPTION_DETECTION_MAGIC_VALUE));
      -
      12743  alignment = VmaAlignUp<VkDeviceSize>(alignment, sizeof(VMA_CORRUPTION_DETECTION_MAGIC_VALUE));
      -
      12744  }
      -
      12745 
      -
      12746  {
      -
      12747  VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
      -
      12748  for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
      -
      12749  {
      -
      12750  res = AllocatePage(
      -
      12751  currentFrameIndex,
      -
      12752  size,
      -
      12753  alignment,
      -
      12754  createInfo,
      -
      12755  suballocType,
      -
      12756  pAllocations + allocIndex);
      -
      12757  if(res != VK_SUCCESS)
      -
      12758  {
      -
      12759  break;
      -
      12760  }
      -
      12761  }
      -
      12762  }
      -
      12763 
      -
      12764  if(res != VK_SUCCESS)
      +
      12740  VmaWriteMagicValue(pData, allocOffset - VMA_DEBUG_MARGIN);
      +
      12741  VmaWriteMagicValue(pData, allocOffset + allocSize);
      +
      12742 
      +
      12743  Unmap(hAllocator, 1);
      +
      12744 
      +
      12745  return VK_SUCCESS;
      +
      12746 }
      +
      12747 
      +
      12748 VkResult VmaDeviceMemoryBlock::ValidateMagicValueAroundAllocation(VmaAllocator hAllocator, VkDeviceSize allocOffset, VkDeviceSize allocSize)
      +
      12749 {
      +
      12750  VMA_ASSERT(VMA_DEBUG_MARGIN > 0 && VMA_DEBUG_MARGIN % 4 == 0 && VMA_DEBUG_DETECT_CORRUPTION);
      +
      12751  VMA_ASSERT(allocOffset >= VMA_DEBUG_MARGIN);
      +
      12752 
      +
      12753  void* pData;
      +
      12754  VkResult res = Map(hAllocator, 1, &pData);
      +
      12755  if(res != VK_SUCCESS)
      +
      12756  {
      +
      12757  return res;
      +
      12758  }
      +
      12759 
      +
      12760  if(!VmaValidateMagicValue(pData, allocOffset - VMA_DEBUG_MARGIN))
      +
      12761  {
      +
      12762  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED BEFORE FREED ALLOCATION!");
      +
      12763  }
      +
      12764  else if(!VmaValidateMagicValue(pData, allocOffset + allocSize))
      12765  {
      -
      12766  // Free all already created allocations.
      -
      12767  while(allocIndex--)
      -
      12768  {
      -
      12769  Free(pAllocations[allocIndex]);
      -
      12770  }
      -
      12771  memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount);
      -
      12772  }
      +
      12766  VMA_ASSERT(0 && "MEMORY CORRUPTION DETECTED AFTER FREED ALLOCATION!");
      +
      12767  }
      +
      12768 
      +
      12769  Unmap(hAllocator, 1);
      +
      12770 
      +
      12771  return VK_SUCCESS;
      +
      12772 }
      12773 
      -
      12774  return res;
      -
      12775 }
      -
      12776 
      -
      12777 VkResult VmaBlockVector::AllocatePage(
      -
      12778  uint32_t currentFrameIndex,
      -
      12779  VkDeviceSize size,
      -
      12780  VkDeviceSize alignment,
      -
      12781  const VmaAllocationCreateInfo& createInfo,
      -
      12782  VmaSuballocationType suballocType,
      -
      12783  VmaAllocation* pAllocation)
      -
      12784 {
      -
      12785  const bool isUpperAddress = (createInfo.flags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0;
      -
      12786  bool canMakeOtherLost = (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT) != 0;
      -
      12787  const bool mapped = (createInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0;
      -
      12788  const bool isUserDataString = (createInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0;
      -
      12789 
      -
      12790  VkDeviceSize freeMemory;
      -
      12791  {
      -
      12792  const uint32_t heapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex);
      -
      12793  VmaBudget heapBudget = {};
      -
      12794  m_hAllocator->GetBudget(&heapBudget, heapIndex, 1);
      -
      12795  freeMemory = (heapBudget.usage < heapBudget.budget) ? (heapBudget.budget - heapBudget.usage) : 0;
      -
      12796  }
      -
      12797 
      -
      12798  const bool canFallbackToDedicated = !IsCustomPool();
      -
      12799  const bool canCreateNewBlock =
      -
      12800  ((createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0) &&
      -
      12801  (m_Blocks.size() < m_MaxBlockCount) &&
      -
      12802  (freeMemory >= size || !canFallbackToDedicated);
      -
      12803  uint32_t strategy = createInfo.flags & VMA_ALLOCATION_CREATE_STRATEGY_MASK;
      -
      12804 
      -
      12805  // If linearAlgorithm is used, canMakeOtherLost is available only when used as ring buffer.
      -
      12806  // Which in turn is available only when maxBlockCount = 1.
      -
      12807  if(m_Algorithm == VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT && m_MaxBlockCount > 1)
      -
      12808  {
      -
      12809  canMakeOtherLost = false;
      -
      12810  }
      -
      12811 
      -
      12812  // Upper address can only be used with linear allocator and within single memory block.
      -
      12813  if(isUpperAddress &&
      -
      12814  (m_Algorithm != VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT || m_MaxBlockCount > 1))
      -
      12815  {
      -
      12816  return VK_ERROR_FEATURE_NOT_PRESENT;
      -
      12817  }
      -
      12818 
      -
      12819  // Validate strategy.
      -
      12820  switch(strategy)
      -
      12821  {
      -
      12822  case 0:
      - -
      12824  break;
      - - - -
      12828  break;
      -
      12829  default:
      -
      12830  return VK_ERROR_FEATURE_NOT_PRESENT;
      -
      12831  }
      -
      12832 
      -
      12833  // Early reject: requested allocation size is larger that maximum block size for this block vector.
      -
      12834  if(size + 2 * VMA_DEBUG_MARGIN > m_PreferredBlockSize)
      -
      12835  {
      -
      12836  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      -
      12837  }
      -
      12838 
      -
      12839  /*
      -
      12840  Under certain condition, this whole section can be skipped for optimization, so
      -
      12841  we move on directly to trying to allocate with canMakeOtherLost. That's the case
      -
      12842  e.g. for custom pools with linear algorithm.
      -
      12843  */
      -
      12844  if(!canMakeOtherLost || canCreateNewBlock)
      -
      12845  {
      -
      12846  // 1. Search existing allocations. Try to allocate without making other allocations lost.
      -
      12847  VmaAllocationCreateFlags allocFlagsCopy = createInfo.flags;
      - -
      12849 
      -
      12850  if(m_Algorithm == VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT)
      -
      12851  {
      -
      12852  // Use only last block.
      -
      12853  if(!m_Blocks.empty())
      -
      12854  {
      -
      12855  VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks.back();
      -
      12856  VMA_ASSERT(pCurrBlock);
      -
      12857  VkResult res = AllocateFromBlock(
      -
      12858  pCurrBlock,
      -
      12859  currentFrameIndex,
      -
      12860  size,
      -
      12861  alignment,
      -
      12862  allocFlagsCopy,
      -
      12863  createInfo.pUserData,
      -
      12864  suballocType,
      -
      12865  strategy,
      -
      12866  pAllocation);
      -
      12867  if(res == VK_SUCCESS)
      -
      12868  {
      -
      12869  VMA_DEBUG_LOG(" Returned from last block #%u", pCurrBlock->GetId());
      -
      12870  return VK_SUCCESS;
      -
      12871  }
      -
      12872  }
      -
      12873  }
      -
      12874  else
      -
      12875  {
      - -
      12877  {
      -
      12878  // Forward order in m_Blocks - prefer blocks with smallest amount of free space.
      -
      12879  for(size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex )
      -
      12880  {
      -
      12881  VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];
      -
      12882  VMA_ASSERT(pCurrBlock);
      -
      12883  VkResult res = AllocateFromBlock(
      -
      12884  pCurrBlock,
      -
      12885  currentFrameIndex,
      -
      12886  size,
      -
      12887  alignment,
      -
      12888  allocFlagsCopy,
      -
      12889  createInfo.pUserData,
      -
      12890  suballocType,
      -
      12891  strategy,
      -
      12892  pAllocation);
      -
      12893  if(res == VK_SUCCESS)
      -
      12894  {
      -
      12895  VMA_DEBUG_LOG(" Returned from existing block #%u", pCurrBlock->GetId());
      -
      12896  return VK_SUCCESS;
      -
      12897  }
      -
      12898  }
      -
      12899  }
      -
      12900  else // WORST_FIT, FIRST_FIT
      -
      12901  {
      -
      12902  // Backward order in m_Blocks - prefer blocks with largest amount of free space.
      -
      12903  for(size_t blockIndex = m_Blocks.size(); blockIndex--; )
      -
      12904  {
      -
      12905  VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];
      -
      12906  VMA_ASSERT(pCurrBlock);
      -
      12907  VkResult res = AllocateFromBlock(
      -
      12908  pCurrBlock,
      -
      12909  currentFrameIndex,
      -
      12910  size,
      -
      12911  alignment,
      -
      12912  allocFlagsCopy,
      -
      12913  createInfo.pUserData,
      -
      12914  suballocType,
      -
      12915  strategy,
      -
      12916  pAllocation);
      -
      12917  if(res == VK_SUCCESS)
      -
      12918  {
      -
      12919  VMA_DEBUG_LOG(" Returned from existing block #%u", pCurrBlock->GetId());
      -
      12920  return VK_SUCCESS;
      -
      12921  }
      -
      12922  }
      -
      12923  }
      -
      12924  }
      -
      12925 
      -
      12926  // 2. Try to create new block.
      -
      12927  if(canCreateNewBlock)
      -
      12928  {
      -
      12929  // Calculate optimal size for new block.
      -
      12930  VkDeviceSize newBlockSize = m_PreferredBlockSize;
      -
      12931  uint32_t newBlockSizeShift = 0;
      -
      12932  const uint32_t NEW_BLOCK_SIZE_SHIFT_MAX = 3;
      -
      12933 
      -
      12934  if(!m_ExplicitBlockSize)
      -
      12935  {
      -
      12936  // Allocate 1/8, 1/4, 1/2 as first blocks.
      -
      12937  const VkDeviceSize maxExistingBlockSize = CalcMaxBlockSize();
      -
      12938  for(uint32_t i = 0; i < NEW_BLOCK_SIZE_SHIFT_MAX; ++i)
      -
      12939  {
      -
      12940  const VkDeviceSize smallerNewBlockSize = newBlockSize / 2;
      -
      12941  if(smallerNewBlockSize > maxExistingBlockSize && smallerNewBlockSize >= size * 2)
      -
      12942  {
      -
      12943  newBlockSize = smallerNewBlockSize;
      -
      12944  ++newBlockSizeShift;
      -
      12945  }
      -
      12946  else
      -
      12947  {
      -
      12948  break;
      -
      12949  }
      -
      12950  }
      -
      12951  }
      -
      12952 
      -
      12953  size_t newBlockIndex = 0;
      -
      12954  VkResult res = (newBlockSize <= freeMemory || !canFallbackToDedicated) ?
      -
      12955  CreateBlock(newBlockSize, &newBlockIndex) : VK_ERROR_OUT_OF_DEVICE_MEMORY;
      -
      12956  // Allocation of this size failed? Try 1/2, 1/4, 1/8 of m_PreferredBlockSize.
      -
      12957  if(!m_ExplicitBlockSize)
      -
      12958  {
      -
      12959  while(res < 0 && newBlockSizeShift < NEW_BLOCK_SIZE_SHIFT_MAX)
      -
      12960  {
      -
      12961  const VkDeviceSize smallerNewBlockSize = newBlockSize / 2;
      -
      12962  if(smallerNewBlockSize >= size)
      -
      12963  {
      -
      12964  newBlockSize = smallerNewBlockSize;
      -
      12965  ++newBlockSizeShift;
      -
      12966  res = (newBlockSize <= freeMemory || !canFallbackToDedicated) ?
      -
      12967  CreateBlock(newBlockSize, &newBlockIndex) : VK_ERROR_OUT_OF_DEVICE_MEMORY;
      -
      12968  }
      -
      12969  else
      -
      12970  {
      -
      12971  break;
      -
      12972  }
      -
      12973  }
      -
      12974  }
      -
      12975 
      -
      12976  if(res == VK_SUCCESS)
      -
      12977  {
      -
      12978  VmaDeviceMemoryBlock* const pBlock = m_Blocks[newBlockIndex];
      -
      12979  VMA_ASSERT(pBlock->m_pMetadata->GetSize() >= size);
      -
      12980 
      -
      12981  res = AllocateFromBlock(
      -
      12982  pBlock,
      -
      12983  currentFrameIndex,
      -
      12984  size,
      -
      12985  alignment,
      -
      12986  allocFlagsCopy,
      -
      12987  createInfo.pUserData,
      -
      12988  suballocType,
      -
      12989  strategy,
      -
      12990  pAllocation);
      -
      12991  if(res == VK_SUCCESS)
      -
      12992  {
      -
      12993  VMA_DEBUG_LOG(" Created new block #%u Size=%llu", pBlock->GetId(), newBlockSize);
      -
      12994  return VK_SUCCESS;
      -
      12995  }
      -
      12996  else
      -
      12997  {
      -
      12998  // Allocation from new block failed, possibly due to VMA_DEBUG_MARGIN or alignment.
      -
      12999  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      -
      13000  }
      -
      13001  }
      -
      13002  }
      -
      13003  }
      -
      13004 
      -
      13005  // 3. Try to allocate from existing blocks with making other allocations lost.
      -
      13006  if(canMakeOtherLost)
      -
      13007  {
      -
      13008  uint32_t tryIndex = 0;
      -
      13009  for(; tryIndex < VMA_ALLOCATION_TRY_COUNT; ++tryIndex)
      -
      13010  {
      -
      13011  VmaDeviceMemoryBlock* pBestRequestBlock = VMA_NULL;
      -
      13012  VmaAllocationRequest bestRequest = {};
      -
      13013  VkDeviceSize bestRequestCost = VK_WHOLE_SIZE;
      -
      13014 
      -
      13015  // 1. Search existing allocations.
      - -
      13017  {
      -
      13018  // Forward order in m_Blocks - prefer blocks with smallest amount of free space.
      -
      13019  for(size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex )
      -
      13020  {
      -
      13021  VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];
      -
      13022  VMA_ASSERT(pCurrBlock);
      -
      13023  VmaAllocationRequest currRequest = {};
      -
      13024  if(pCurrBlock->m_pMetadata->CreateAllocationRequest(
      -
      13025  currentFrameIndex,
      -
      13026  m_FrameInUseCount,
      -
      13027  m_BufferImageGranularity,
      -
      13028  size,
      -
      13029  alignment,
      -
      13030  (createInfo.flags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0,
      -
      13031  suballocType,
      -
      13032  canMakeOtherLost,
      -
      13033  strategy,
      -
      13034  &currRequest))
      -
      13035  {
      -
      13036  const VkDeviceSize currRequestCost = currRequest.CalcCost();
      -
      13037  if(pBestRequestBlock == VMA_NULL ||
      -
      13038  currRequestCost < bestRequestCost)
      -
      13039  {
      -
      13040  pBestRequestBlock = pCurrBlock;
      -
      13041  bestRequest = currRequest;
      -
      13042  bestRequestCost = currRequestCost;
      -
      13043 
      -
      13044  if(bestRequestCost == 0)
      -
      13045  {
      -
      13046  break;
      -
      13047  }
      -
      13048  }
      -
      13049  }
      -
      13050  }
      -
      13051  }
      -
      13052  else // WORST_FIT, FIRST_FIT
      -
      13053  {
      -
      13054  // Backward order in m_Blocks - prefer blocks with largest amount of free space.
      -
      13055  for(size_t blockIndex = m_Blocks.size(); blockIndex--; )
      -
      13056  {
      -
      13057  VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];
      -
      13058  VMA_ASSERT(pCurrBlock);
      -
      13059  VmaAllocationRequest currRequest = {};
      -
      13060  if(pCurrBlock->m_pMetadata->CreateAllocationRequest(
      -
      13061  currentFrameIndex,
      -
      13062  m_FrameInUseCount,
      -
      13063  m_BufferImageGranularity,
      -
      13064  size,
      -
      13065  alignment,
      -
      13066  (createInfo.flags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0,
      -
      13067  suballocType,
      -
      13068  canMakeOtherLost,
      -
      13069  strategy,
      -
      13070  &currRequest))
      -
      13071  {
      -
      13072  const VkDeviceSize currRequestCost = currRequest.CalcCost();
      -
      13073  if(pBestRequestBlock == VMA_NULL ||
      -
      13074  currRequestCost < bestRequestCost ||
      - -
      13076  {
      -
      13077  pBestRequestBlock = pCurrBlock;
      -
      13078  bestRequest = currRequest;
      -
      13079  bestRequestCost = currRequestCost;
      +
      12774 VkResult VmaDeviceMemoryBlock::BindBufferMemory(
      +
      12775  const VmaAllocator hAllocator,
      +
      12776  const VmaAllocation hAllocation,
      +
      12777  VkDeviceSize allocationLocalOffset,
      +
      12778  VkBuffer hBuffer,
      +
      12779  const void* pNext)
      +
      12780 {
      +
      12781  VMA_ASSERT(hAllocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK &&
      +
      12782  hAllocation->GetBlock() == this);
      +
      12783  VMA_ASSERT(allocationLocalOffset < hAllocation->GetSize() &&
      +
      12784  "Invalid allocationLocalOffset. Did you forget that this offset is relative to the beginning of the allocation, not the whole memory block?");
      +
      12785  const VkDeviceSize memoryOffset = hAllocation->GetOffset() + allocationLocalOffset;
      +
      12786  // This lock is important so that we don't call vkBind... and/or vkMap... simultaneously on the same VkDeviceMemory from multiple threads.
      +
      12787  VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex);
      +
      12788  return hAllocator->BindVulkanBuffer(m_hMemory, memoryOffset, hBuffer, pNext);
      +
      12789 }
      +
      12790 
      +
      12791 VkResult VmaDeviceMemoryBlock::BindImageMemory(
      +
      12792  const VmaAllocator hAllocator,
      +
      12793  const VmaAllocation hAllocation,
      +
      12794  VkDeviceSize allocationLocalOffset,
      +
      12795  VkImage hImage,
      +
      12796  const void* pNext)
      +
      12797 {
      +
      12798  VMA_ASSERT(hAllocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK &&
      +
      12799  hAllocation->GetBlock() == this);
      +
      12800  VMA_ASSERT(allocationLocalOffset < hAllocation->GetSize() &&
      +
      12801  "Invalid allocationLocalOffset. Did you forget that this offset is relative to the beginning of the allocation, not the whole memory block?");
      +
      12802  const VkDeviceSize memoryOffset = hAllocation->GetOffset() + allocationLocalOffset;
      +
      12803  // This lock is important so that we don't call vkBind... and/or vkMap... simultaneously on the same VkDeviceMemory from multiple threads.
      +
      12804  VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex);
      +
      12805  return hAllocator->BindVulkanImage(m_hMemory, memoryOffset, hImage, pNext);
      +
      12806 }
      +
      12807 
      +
      12808 static void InitStatInfo(VmaStatInfo& outInfo)
      +
      12809 {
      +
      12810  memset(&outInfo, 0, sizeof(outInfo));
      +
      12811  outInfo.allocationSizeMin = UINT64_MAX;
      +
      12812  outInfo.unusedRangeSizeMin = UINT64_MAX;
      +
      12813 }
      +
      12814 
      +
      12815 // Adds statistics srcInfo into inoutInfo, like: inoutInfo += srcInfo.
      +
      12816 static void VmaAddStatInfo(VmaStatInfo& inoutInfo, const VmaStatInfo& srcInfo)
      +
      12817 {
      +
      12818  inoutInfo.blockCount += srcInfo.blockCount;
      +
      12819  inoutInfo.allocationCount += srcInfo.allocationCount;
      +
      12820  inoutInfo.unusedRangeCount += srcInfo.unusedRangeCount;
      +
      12821  inoutInfo.usedBytes += srcInfo.usedBytes;
      +
      12822  inoutInfo.unusedBytes += srcInfo.unusedBytes;
      +
      12823  inoutInfo.allocationSizeMin = VMA_MIN(inoutInfo.allocationSizeMin, srcInfo.allocationSizeMin);
      +
      12824  inoutInfo.allocationSizeMax = VMA_MAX(inoutInfo.allocationSizeMax, srcInfo.allocationSizeMax);
      +
      12825  inoutInfo.unusedRangeSizeMin = VMA_MIN(inoutInfo.unusedRangeSizeMin, srcInfo.unusedRangeSizeMin);
      +
      12826  inoutInfo.unusedRangeSizeMax = VMA_MAX(inoutInfo.unusedRangeSizeMax, srcInfo.unusedRangeSizeMax);
      +
      12827 }
      +
      12828 
      +
      12829 static void VmaPostprocessCalcStatInfo(VmaStatInfo& inoutInfo)
      +
      12830 {
      +
      12831  inoutInfo.allocationSizeAvg = (inoutInfo.allocationCount > 0) ?
      +
      12832  VmaRoundDiv<VkDeviceSize>(inoutInfo.usedBytes, inoutInfo.allocationCount) : 0;
      +
      12833  inoutInfo.unusedRangeSizeAvg = (inoutInfo.unusedRangeCount > 0) ?
      +
      12834  VmaRoundDiv<VkDeviceSize>(inoutInfo.unusedBytes, inoutInfo.unusedRangeCount) : 0;
      +
      12835 }
      +
      12836 
      +
      12837 VmaPool_T::VmaPool_T(
      +
      12838  VmaAllocator hAllocator,
      +
      12839  const VmaPoolCreateInfo& createInfo,
      +
      12840  VkDeviceSize preferredBlockSize) :
      +
      12841  m_BlockVector(
      +
      12842  hAllocator,
      +
      12843  this, // hParentPool
      +
      12844  createInfo.memoryTypeIndex,
      +
      12845  createInfo.blockSize != 0 ? createInfo.blockSize : preferredBlockSize,
      +
      12846  createInfo.minBlockCount,
      +
      12847  createInfo.maxBlockCount,
      +
      12848  (createInfo.flags & VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT) != 0 ? 1 : hAllocator->GetBufferImageGranularity(),
      +
      12849  createInfo.frameInUseCount,
      +
      12850  createInfo.blockSize != 0, // explicitBlockSize
      +
      12851  createInfo.flags & VMA_POOL_CREATE_ALGORITHM_MASK,
      +
      12852  createInfo.priority), // algorithm
      +
      12853  m_Id(0),
      +
      12854  m_Name(VMA_NULL)
      +
      12855 {
      +
      12856 }
      +
      12857 
      +
      12858 VmaPool_T::~VmaPool_T()
      +
      12859 {
      +
      12860  VMA_ASSERT(m_PrevPool == VMA_NULL && m_NextPool == VMA_NULL);
      +
      12861 }
      +
      12862 
      +
      12863 void VmaPool_T::SetName(const char* pName)
      +
      12864 {
      +
      12865  const VkAllocationCallbacks* allocs = m_BlockVector.GetAllocator()->GetAllocationCallbacks();
      +
      12866  VmaFreeString(allocs, m_Name);
      +
      12867 
      +
      12868  if(pName != VMA_NULL)
      +
      12869  {
      +
      12870  m_Name = VmaCreateStringCopy(allocs, pName);
      +
      12871  }
      +
      12872  else
      +
      12873  {
      +
      12874  m_Name = VMA_NULL;
      +
      12875  }
      +
      12876 }
      +
      12877 
      +
      12878 #if VMA_STATS_STRING_ENABLED
      +
      12879 
      +
      12880 #endif // #if VMA_STATS_STRING_ENABLED
      +
      12881 
      +
      12882 VmaBlockVector::VmaBlockVector(
      +
      12883  VmaAllocator hAllocator,
      +
      12884  VmaPool hParentPool,
      +
      12885  uint32_t memoryTypeIndex,
      +
      12886  VkDeviceSize preferredBlockSize,
      +
      12887  size_t minBlockCount,
      +
      12888  size_t maxBlockCount,
      +
      12889  VkDeviceSize bufferImageGranularity,
      +
      12890  uint32_t frameInUseCount,
      +
      12891  bool explicitBlockSize,
      +
      12892  uint32_t algorithm,
      +
      12893  float priority) :
      +
      12894  m_hAllocator(hAllocator),
      +
      12895  m_hParentPool(hParentPool),
      +
      12896  m_MemoryTypeIndex(memoryTypeIndex),
      +
      12897  m_PreferredBlockSize(preferredBlockSize),
      +
      12898  m_MinBlockCount(minBlockCount),
      +
      12899  m_MaxBlockCount(maxBlockCount),
      +
      12900  m_BufferImageGranularity(bufferImageGranularity),
      +
      12901  m_FrameInUseCount(frameInUseCount),
      +
      12902  m_ExplicitBlockSize(explicitBlockSize),
      +
      12903  m_Algorithm(algorithm),
      +
      12904  m_Priority(priority),
      +
      12905  m_HasEmptyBlock(false),
      +
      12906  m_Blocks(VmaStlAllocator<VmaDeviceMemoryBlock*>(hAllocator->GetAllocationCallbacks())),
      +
      12907  m_NextBlockId(0)
      +
      12908 {
      +
      12909 }
      +
      12910 
      +
      12911 VmaBlockVector::~VmaBlockVector()
      +
      12912 {
      +
      12913  for(size_t i = m_Blocks.size(); i--; )
      +
      12914  {
      +
      12915  m_Blocks[i]->Destroy(m_hAllocator);
      +
      12916  vma_delete(m_hAllocator, m_Blocks[i]);
      +
      12917  }
      +
      12918 }
      +
      12919 
      +
      12920 VkResult VmaBlockVector::CreateMinBlocks()
      +
      12921 {
      +
      12922  for(size_t i = 0; i < m_MinBlockCount; ++i)
      +
      12923  {
      +
      12924  VkResult res = CreateBlock(m_PreferredBlockSize, VMA_NULL);
      +
      12925  if(res != VK_SUCCESS)
      +
      12926  {
      +
      12927  return res;
      +
      12928  }
      +
      12929  }
      +
      12930  return VK_SUCCESS;
      +
      12931 }
      +
      12932 
      +
      12933 void VmaBlockVector::GetPoolStats(VmaPoolStats* pStats)
      +
      12934 {
      +
      12935  VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex);
      +
      12936 
      +
      12937  const size_t blockCount = m_Blocks.size();
      +
      12938 
      +
      12939  pStats->size = 0;
      +
      12940  pStats->unusedSize = 0;
      +
      12941  pStats->allocationCount = 0;
      +
      12942  pStats->unusedRangeCount = 0;
      +
      12943  pStats->unusedRangeSizeMax = 0;
      +
      12944  pStats->blockCount = blockCount;
      +
      12945 
      +
      12946  for(uint32_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
      +
      12947  {
      +
      12948  const VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex];
      +
      12949  VMA_ASSERT(pBlock);
      +
      12950  VMA_HEAVY_ASSERT(pBlock->Validate());
      +
      12951  pBlock->m_pMetadata->AddPoolStats(*pStats);
      +
      12952  }
      +
      12953 }
      +
      12954 
      +
      12955 bool VmaBlockVector::IsEmpty()
      +
      12956 {
      +
      12957  VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex);
      +
      12958  return m_Blocks.empty();
      +
      12959 }
      +
      12960 
      +
      12961 bool VmaBlockVector::IsCorruptionDetectionEnabled() const
      +
      12962 {
      +
      12963  const uint32_t requiredMemFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
      +
      12964  return (VMA_DEBUG_DETECT_CORRUPTION != 0) &&
      +
      12965  (VMA_DEBUG_MARGIN > 0) &&
      +
      12966  (m_Algorithm == 0 || m_Algorithm == VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT) &&
      +
      12967  (m_hAllocator->m_MemProps.memoryTypes[m_MemoryTypeIndex].propertyFlags & requiredMemFlags) == requiredMemFlags;
      +
      12968 }
      +
      12969 
      +
      12970 static const uint32_t VMA_ALLOCATION_TRY_COUNT = 32;
      +
      12971 
      +
      12972 VkResult VmaBlockVector::Allocate(
      +
      12973  uint32_t currentFrameIndex,
      +
      12974  VkDeviceSize size,
      +
      12975  VkDeviceSize alignment,
      +
      12976  const VmaAllocationCreateInfo& createInfo,
      +
      12977  VmaSuballocationType suballocType,
      +
      12978  size_t allocationCount,
      +
      12979  VmaAllocation* pAllocations)
      +
      12980 {
      +
      12981  size_t allocIndex;
      +
      12982  VkResult res = VK_SUCCESS;
      +
      12983 
      +
      12984  if(IsCorruptionDetectionEnabled())
      +
      12985  {
      +
      12986  size = VmaAlignUp<VkDeviceSize>(size, sizeof(VMA_CORRUPTION_DETECTION_MAGIC_VALUE));
      +
      12987  alignment = VmaAlignUp<VkDeviceSize>(alignment, sizeof(VMA_CORRUPTION_DETECTION_MAGIC_VALUE));
      +
      12988  }
      +
      12989 
      +
      12990  {
      +
      12991  VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
      +
      12992  for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
      +
      12993  {
      +
      12994  res = AllocatePage(
      +
      12995  currentFrameIndex,
      +
      12996  size,
      +
      12997  alignment,
      +
      12998  createInfo,
      +
      12999  suballocType,
      +
      13000  pAllocations + allocIndex);
      +
      13001  if(res != VK_SUCCESS)
      +
      13002  {
      +
      13003  break;
      +
      13004  }
      +
      13005  }
      +
      13006  }
      +
      13007 
      +
      13008  if(res != VK_SUCCESS)
      +
      13009  {
      +
      13010  // Free all already created allocations.
      +
      13011  const uint32_t heapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex);
      +
      13012  while(allocIndex--)
      +
      13013  {
      +
      13014  VmaAllocation_T* const alloc = pAllocations[allocIndex];
      +
      13015  const VkDeviceSize allocSize = alloc->GetSize();
      +
      13016  Free(alloc);
      +
      13017  m_hAllocator->m_Budget.RemoveAllocation(heapIndex, allocSize);
      +
      13018  }
      +
      13019  memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount);
      +
      13020  }
      +
      13021 
      +
      13022  return res;
      +
      13023 }
      +
      13024 
      +
      13025 VkResult VmaBlockVector::AllocatePage(
      +
      13026  uint32_t currentFrameIndex,
      +
      13027  VkDeviceSize size,
      +
      13028  VkDeviceSize alignment,
      +
      13029  const VmaAllocationCreateInfo& createInfo,
      +
      13030  VmaSuballocationType suballocType,
      +
      13031  VmaAllocation* pAllocation)
      +
      13032 {
      +
      13033  const bool isUpperAddress = (createInfo.flags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0;
      +
      13034  bool canMakeOtherLost = (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT) != 0;
      +
      13035  const bool mapped = (createInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0;
      +
      13036  const bool isUserDataString = (createInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0;
      +
      13037 
      +
      13038  VkDeviceSize freeMemory;
      +
      13039  {
      +
      13040  const uint32_t heapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex);
      +
      13041  VmaBudget heapBudget = {};
      +
      13042  m_hAllocator->GetBudget(&heapBudget, heapIndex, 1);
      +
      13043  freeMemory = (heapBudget.usage < heapBudget.budget) ? (heapBudget.budget - heapBudget.usage) : 0;
      +
      13044  }
      +
      13045 
      +
      13046  const bool canFallbackToDedicated = !IsCustomPool();
      +
      13047  const bool canCreateNewBlock =
      +
      13048  ((createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0) &&
      +
      13049  (m_Blocks.size() < m_MaxBlockCount) &&
      +
      13050  (freeMemory >= size || !canFallbackToDedicated);
      +
      13051  uint32_t strategy = createInfo.flags & VMA_ALLOCATION_CREATE_STRATEGY_MASK;
      +
      13052 
      +
      13053  // If linearAlgorithm is used, canMakeOtherLost is available only when used as ring buffer.
      +
      13054  // Which in turn is available only when maxBlockCount = 1.
      +
      13055  if(m_Algorithm == VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT && m_MaxBlockCount > 1)
      +
      13056  {
      +
      13057  canMakeOtherLost = false;
      +
      13058  }
      +
      13059 
      +
      13060  // Upper address can only be used with linear allocator and within single memory block.
      +
      13061  if(isUpperAddress &&
      +
      13062  (m_Algorithm != VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT || m_MaxBlockCount > 1))
      +
      13063  {
      +
      13064  return VK_ERROR_FEATURE_NOT_PRESENT;
      +
      13065  }
      +
      13066 
      +
      13067  // Validate strategy.
      +
      13068  switch(strategy)
      +
      13069  {
      +
      13070  case 0:
      + +
      13072  break;
      + + + +
      13076  break;
      +
      13077  default:
      +
      13078  return VK_ERROR_FEATURE_NOT_PRESENT;
      +
      13079  }
      13080 
      -
      13081  if(bestRequestCost == 0 ||
      - -
      13083  {
      -
      13084  break;
      -
      13085  }
      -
      13086  }
      -
      13087  }
      -
      13088  }
      -
      13089  }
      -
      13090 
      -
      13091  if(pBestRequestBlock != VMA_NULL)
      -
      13092  {
      -
      13093  if(mapped)
      -
      13094  {
      -
      13095  VkResult res = pBestRequestBlock->Map(m_hAllocator, 1, VMA_NULL);
      -
      13096  if(res != VK_SUCCESS)
      -
      13097  {
      -
      13098  return res;
      -
      13099  }
      -
      13100  }
      -
      13101 
      -
      13102  if(pBestRequestBlock->m_pMetadata->MakeRequestedAllocationsLost(
      -
      13103  currentFrameIndex,
      -
      13104  m_FrameInUseCount,
      -
      13105  &bestRequest))
      -
      13106  {
      -
      13107  // Allocate from this pBlock.
      -
      13108  *pAllocation = m_hAllocator->m_AllocationObjectAllocator.Allocate(currentFrameIndex, isUserDataString);
      -
      13109  pBestRequestBlock->m_pMetadata->Alloc(bestRequest, suballocType, size, *pAllocation);
      -
      13110  UpdateHasEmptyBlock();
      -
      13111  (*pAllocation)->InitBlockAllocation(
      -
      13112  pBestRequestBlock,
      -
      13113  bestRequest.offset,
      -
      13114  alignment,
      -
      13115  size,
      -
      13116  m_MemoryTypeIndex,
      -
      13117  suballocType,
      -
      13118  mapped,
      -
      13119  (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0);
      -
      13120  VMA_HEAVY_ASSERT(pBestRequestBlock->Validate());
      -
      13121  VMA_DEBUG_LOG(" Returned from existing block");
      -
      13122  (*pAllocation)->SetUserData(m_hAllocator, createInfo.pUserData);
      -
      13123  m_hAllocator->m_Budget.AddAllocation(m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex), size);
      -
      13124  if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
      -
      13125  {
      -
      13126  m_hAllocator->FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED);
      -
      13127  }
      -
      13128  if(IsCorruptionDetectionEnabled())
      -
      13129  {
      -
      13130  VkResult res = pBestRequestBlock->WriteMagicValueAroundAllocation(m_hAllocator, bestRequest.offset, size);
      -
      13131  VMA_ASSERT(res == VK_SUCCESS && "Couldn't map block memory to write magic value.");
      -
      13132  }
      -
      13133  return VK_SUCCESS;
      -
      13134  }
      -
      13135  // else: Some allocations must have been touched while we are here. Next try.
      -
      13136  }
      -
      13137  else
      -
      13138  {
      -
      13139  // Could not find place in any of the blocks - break outer loop.
      -
      13140  break;
      -
      13141  }
      -
      13142  }
      -
      13143  /* Maximum number of tries exceeded - a very unlike event when many other
      -
      13144  threads are simultaneously touching allocations making it impossible to make
      -
      13145  lost at the same time as we try to allocate. */
      -
      13146  if(tryIndex == VMA_ALLOCATION_TRY_COUNT)
      -
      13147  {
      -
      13148  return VK_ERROR_TOO_MANY_OBJECTS;
      -
      13149  }
      -
      13150  }
      -
      13151 
      -
      13152  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      -
      13153 }
      -
      13154 
      -
      13155 void VmaBlockVector::Free(
      -
      13156  const VmaAllocation hAllocation)
      -
      13157 {
      -
      13158  VmaDeviceMemoryBlock* pBlockToDelete = VMA_NULL;
      -
      13159 
      -
      13160  bool budgetExceeded = false;
      -
      13161  {
      -
      13162  const uint32_t heapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex);
      -
      13163  VmaBudget heapBudget = {};
      -
      13164  m_hAllocator->GetBudget(&heapBudget, heapIndex, 1);
      -
      13165  budgetExceeded = heapBudget.usage >= heapBudget.budget;
      -
      13166  }
      -
      13167 
      -
      13168  // Scope for lock.
      -
      13169  {
      -
      13170  VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
      -
      13171 
      -
      13172  VmaDeviceMemoryBlock* pBlock = hAllocation->GetBlock();
      +
      13081  // Early reject: requested allocation size is larger that maximum block size for this block vector.
      +
      13082  if(size + 2 * VMA_DEBUG_MARGIN > m_PreferredBlockSize)
      +
      13083  {
      +
      13084  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      +
      13085  }
      +
      13086 
      +
      13087  /*
      +
      13088  Under certain condition, this whole section can be skipped for optimization, so
      +
      13089  we move on directly to trying to allocate with canMakeOtherLost. That's the case
      +
      13090  e.g. for custom pools with linear algorithm.
      +
      13091  */
      +
      13092  if(!canMakeOtherLost || canCreateNewBlock)
      +
      13093  {
      +
      13094  // 1. Search existing allocations. Try to allocate without making other allocations lost.
      +
      13095  VmaAllocationCreateFlags allocFlagsCopy = createInfo.flags;
      + +
      13097 
      +
      13098  if(m_Algorithm == VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT)
      +
      13099  {
      +
      13100  // Use only last block.
      +
      13101  if(!m_Blocks.empty())
      +
      13102  {
      +
      13103  VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks.back();
      +
      13104  VMA_ASSERT(pCurrBlock);
      +
      13105  VkResult res = AllocateFromBlock(
      +
      13106  pCurrBlock,
      +
      13107  currentFrameIndex,
      +
      13108  size,
      +
      13109  alignment,
      +
      13110  allocFlagsCopy,
      +
      13111  createInfo.pUserData,
      +
      13112  suballocType,
      +
      13113  strategy,
      +
      13114  pAllocation);
      +
      13115  if(res == VK_SUCCESS)
      +
      13116  {
      +
      13117  VMA_DEBUG_LOG(" Returned from last block #%u", pCurrBlock->GetId());
      +
      13118  return VK_SUCCESS;
      +
      13119  }
      +
      13120  }
      +
      13121  }
      +
      13122  else
      +
      13123  {
      + +
      13125  {
      +
      13126  // Forward order in m_Blocks - prefer blocks with smallest amount of free space.
      +
      13127  for(size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex )
      +
      13128  {
      +
      13129  VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];
      +
      13130  VMA_ASSERT(pCurrBlock);
      +
      13131  VkResult res = AllocateFromBlock(
      +
      13132  pCurrBlock,
      +
      13133  currentFrameIndex,
      +
      13134  size,
      +
      13135  alignment,
      +
      13136  allocFlagsCopy,
      +
      13137  createInfo.pUserData,
      +
      13138  suballocType,
      +
      13139  strategy,
      +
      13140  pAllocation);
      +
      13141  if(res == VK_SUCCESS)
      +
      13142  {
      +
      13143  VMA_DEBUG_LOG(" Returned from existing block #%u", pCurrBlock->GetId());
      +
      13144  return VK_SUCCESS;
      +
      13145  }
      +
      13146  }
      +
      13147  }
      +
      13148  else // WORST_FIT, FIRST_FIT
      +
      13149  {
      +
      13150  // Backward order in m_Blocks - prefer blocks with largest amount of free space.
      +
      13151  for(size_t blockIndex = m_Blocks.size(); blockIndex--; )
      +
      13152  {
      +
      13153  VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];
      +
      13154  VMA_ASSERT(pCurrBlock);
      +
      13155  VkResult res = AllocateFromBlock(
      +
      13156  pCurrBlock,
      +
      13157  currentFrameIndex,
      +
      13158  size,
      +
      13159  alignment,
      +
      13160  allocFlagsCopy,
      +
      13161  createInfo.pUserData,
      +
      13162  suballocType,
      +
      13163  strategy,
      +
      13164  pAllocation);
      +
      13165  if(res == VK_SUCCESS)
      +
      13166  {
      +
      13167  VMA_DEBUG_LOG(" Returned from existing block #%u", pCurrBlock->GetId());
      +
      13168  return VK_SUCCESS;
      +
      13169  }
      +
      13170  }
      +
      13171  }
      +
      13172  }
      13173 
      -
      13174  if(IsCorruptionDetectionEnabled())
      -
      13175  {
      -
      13176  VkResult res = pBlock->ValidateMagicValueAroundAllocation(m_hAllocator, hAllocation->GetOffset(), hAllocation->GetSize());
      -
      13177  VMA_ASSERT(res == VK_SUCCESS && "Couldn't map block memory to validate magic value.");
      -
      13178  }
      -
      13179 
      -
      13180  if(hAllocation->IsPersistentMap())
      -
      13181  {
      -
      13182  pBlock->Unmap(m_hAllocator, 1);
      -
      13183  }
      -
      13184 
      -
      13185  pBlock->m_pMetadata->Free(hAllocation);
      -
      13186  VMA_HEAVY_ASSERT(pBlock->Validate());
      -
      13187 
      -
      13188  VMA_DEBUG_LOG(" Freed from MemoryTypeIndex=%u", m_MemoryTypeIndex);
      -
      13189 
      -
      13190  const bool canDeleteBlock = m_Blocks.size() > m_MinBlockCount;
      -
      13191  // pBlock became empty after this deallocation.
      -
      13192  if(pBlock->m_pMetadata->IsEmpty())
      -
      13193  {
      -
      13194  // Already has empty block. We don't want to have two, so delete this one.
      -
      13195  if((m_HasEmptyBlock || budgetExceeded) && canDeleteBlock)
      -
      13196  {
      -
      13197  pBlockToDelete = pBlock;
      -
      13198  Remove(pBlock);
      +
      13174  // 2. Try to create new block.
      +
      13175  if(canCreateNewBlock)
      +
      13176  {
      +
      13177  // Calculate optimal size for new block.
      +
      13178  VkDeviceSize newBlockSize = m_PreferredBlockSize;
      +
      13179  uint32_t newBlockSizeShift = 0;
      +
      13180  const uint32_t NEW_BLOCK_SIZE_SHIFT_MAX = 3;
      +
      13181 
      +
      13182  if(!m_ExplicitBlockSize)
      +
      13183  {
      +
      13184  // Allocate 1/8, 1/4, 1/2 as first blocks.
      +
      13185  const VkDeviceSize maxExistingBlockSize = CalcMaxBlockSize();
      +
      13186  for(uint32_t i = 0; i < NEW_BLOCK_SIZE_SHIFT_MAX; ++i)
      +
      13187  {
      +
      13188  const VkDeviceSize smallerNewBlockSize = newBlockSize / 2;
      +
      13189  if(smallerNewBlockSize > maxExistingBlockSize && smallerNewBlockSize >= size * 2)
      +
      13190  {
      +
      13191  newBlockSize = smallerNewBlockSize;
      +
      13192  ++newBlockSizeShift;
      +
      13193  }
      +
      13194  else
      +
      13195  {
      +
      13196  break;
      +
      13197  }
      +
      13198  }
      13199  }
      -
      13200  // else: We now have an empty block - leave it.
      -
      13201  }
      -
      13202  // pBlock didn't become empty, but we have another empty block - find and free that one.
      -
      13203  // (This is optional, heuristics.)
      -
      13204  else if(m_HasEmptyBlock && canDeleteBlock)
      -
      13205  {
      -
      13206  VmaDeviceMemoryBlock* pLastBlock = m_Blocks.back();
      -
      13207  if(pLastBlock->m_pMetadata->IsEmpty())
      -
      13208  {
      -
      13209  pBlockToDelete = pLastBlock;
      -
      13210  m_Blocks.pop_back();
      -
      13211  }
      -
      13212  }
      -
      13213 
      -
      13214  UpdateHasEmptyBlock();
      -
      13215  IncrementallySortBlocks();
      -
      13216  }
      -
      13217 
      -
      13218  // Destruction of a free block. Deferred until this point, outside of mutex
      -
      13219  // lock, for performance reason.
      -
      13220  if(pBlockToDelete != VMA_NULL)
      -
      13221  {
      -
      13222  VMA_DEBUG_LOG(" Deleted empty block");
      -
      13223  pBlockToDelete->Destroy(m_hAllocator);
      -
      13224  vma_delete(m_hAllocator, pBlockToDelete);
      -
      13225  }
      -
      13226 }
      -
      13227 
      -
      13228 VkDeviceSize VmaBlockVector::CalcMaxBlockSize() const
      -
      13229 {
      -
      13230  VkDeviceSize result = 0;
      -
      13231  for(size_t i = m_Blocks.size(); i--; )
      -
      13232  {
      -
      13233  result = VMA_MAX(result, m_Blocks[i]->m_pMetadata->GetSize());
      -
      13234  if(result >= m_PreferredBlockSize)
      -
      13235  {
      -
      13236  break;
      -
      13237  }
      -
      13238  }
      -
      13239  return result;
      -
      13240 }
      -
      13241 
      -
      13242 void VmaBlockVector::Remove(VmaDeviceMemoryBlock* pBlock)
      -
      13243 {
      -
      13244  for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
      -
      13245  {
      -
      13246  if(m_Blocks[blockIndex] == pBlock)
      -
      13247  {
      -
      13248  VmaVectorRemove(m_Blocks, blockIndex);
      -
      13249  return;
      +
      13200 
      +
      13201  size_t newBlockIndex = 0;
      +
      13202  VkResult res = (newBlockSize <= freeMemory || !canFallbackToDedicated) ?
      +
      13203  CreateBlock(newBlockSize, &newBlockIndex) : VK_ERROR_OUT_OF_DEVICE_MEMORY;
      +
      13204  // Allocation of this size failed? Try 1/2, 1/4, 1/8 of m_PreferredBlockSize.
      +
      13205  if(!m_ExplicitBlockSize)
      +
      13206  {
      +
      13207  while(res < 0 && newBlockSizeShift < NEW_BLOCK_SIZE_SHIFT_MAX)
      +
      13208  {
      +
      13209  const VkDeviceSize smallerNewBlockSize = newBlockSize / 2;
      +
      13210  if(smallerNewBlockSize >= size)
      +
      13211  {
      +
      13212  newBlockSize = smallerNewBlockSize;
      +
      13213  ++newBlockSizeShift;
      +
      13214  res = (newBlockSize <= freeMemory || !canFallbackToDedicated) ?
      +
      13215  CreateBlock(newBlockSize, &newBlockIndex) : VK_ERROR_OUT_OF_DEVICE_MEMORY;
      +
      13216  }
      +
      13217  else
      +
      13218  {
      +
      13219  break;
      +
      13220  }
      +
      13221  }
      +
      13222  }
      +
      13223 
      +
      13224  if(res == VK_SUCCESS)
      +
      13225  {
      +
      13226  VmaDeviceMemoryBlock* const pBlock = m_Blocks[newBlockIndex];
      +
      13227  VMA_ASSERT(pBlock->m_pMetadata->GetSize() >= size);
      +
      13228 
      +
      13229  res = AllocateFromBlock(
      +
      13230  pBlock,
      +
      13231  currentFrameIndex,
      +
      13232  size,
      +
      13233  alignment,
      +
      13234  allocFlagsCopy,
      +
      13235  createInfo.pUserData,
      +
      13236  suballocType,
      +
      13237  strategy,
      +
      13238  pAllocation);
      +
      13239  if(res == VK_SUCCESS)
      +
      13240  {
      +
      13241  VMA_DEBUG_LOG(" Created new block #%u Size=%llu", pBlock->GetId(), newBlockSize);
      +
      13242  return VK_SUCCESS;
      +
      13243  }
      +
      13244  else
      +
      13245  {
      +
      13246  // Allocation from new block failed, possibly due to VMA_DEBUG_MARGIN or alignment.
      +
      13247  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      +
      13248  }
      +
      13249  }
      13250  }
      13251  }
      -
      13252  VMA_ASSERT(0);
      -
      13253 }
      -
      13254 
      -
      13255 void VmaBlockVector::IncrementallySortBlocks()
      -
      13256 {
      -
      13257  if(m_Algorithm != VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT)
      -
      13258  {
      -
      13259  // Bubble sort only until first swap.
      -
      13260  for(size_t i = 1; i < m_Blocks.size(); ++i)
      -
      13261  {
      -
      13262  if(m_Blocks[i - 1]->m_pMetadata->GetSumFreeSize() > m_Blocks[i]->m_pMetadata->GetSumFreeSize())
      -
      13263  {
      -
      13264  VMA_SWAP(m_Blocks[i - 1], m_Blocks[i]);
      -
      13265  return;
      -
      13266  }
      -
      13267  }
      -
      13268  }
      -
      13269 }
      -
      13270 
      -
      13271 VkResult VmaBlockVector::AllocateFromBlock(
      -
      13272  VmaDeviceMemoryBlock* pBlock,
      -
      13273  uint32_t currentFrameIndex,
      -
      13274  VkDeviceSize size,
      -
      13275  VkDeviceSize alignment,
      -
      13276  VmaAllocationCreateFlags allocFlags,
      -
      13277  void* pUserData,
      -
      13278  VmaSuballocationType suballocType,
      -
      13279  uint32_t strategy,
      -
      13280  VmaAllocation* pAllocation)
      -
      13281 {
      -
      13282  VMA_ASSERT((allocFlags & VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT) == 0);
      -
      13283  const bool isUpperAddress = (allocFlags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0;
      -
      13284  const bool mapped = (allocFlags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0;
      -
      13285  const bool isUserDataString = (allocFlags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0;
      -
      13286 
      -
      13287  VmaAllocationRequest currRequest = {};
      -
      13288  if(pBlock->m_pMetadata->CreateAllocationRequest(
      -
      13289  currentFrameIndex,
      -
      13290  m_FrameInUseCount,
      -
      13291  m_BufferImageGranularity,
      -
      13292  size,
      -
      13293  alignment,
      -
      13294  isUpperAddress,
      -
      13295  suballocType,
      -
      13296  false, // canMakeOtherLost
      -
      13297  strategy,
      -
      13298  &currRequest))
      -
      13299  {
      -
      13300  // Allocate from pCurrBlock.
      -
      13301  VMA_ASSERT(currRequest.itemsToMakeLostCount == 0);
      -
      13302 
      -
      13303  if(mapped)
      -
      13304  {
      -
      13305  VkResult res = pBlock->Map(m_hAllocator, 1, VMA_NULL);
      -
      13306  if(res != VK_SUCCESS)
      -
      13307  {
      -
      13308  return res;
      -
      13309  }
      -
      13310  }
      -
      13311 
      -
      13312  *pAllocation = m_hAllocator->m_AllocationObjectAllocator.Allocate(currentFrameIndex, isUserDataString);
      -
      13313  pBlock->m_pMetadata->Alloc(currRequest, suballocType, size, *pAllocation);
      -
      13314  UpdateHasEmptyBlock();
      -
      13315  (*pAllocation)->InitBlockAllocation(
      -
      13316  pBlock,
      -
      13317  currRequest.offset,
      -
      13318  alignment,
      -
      13319  size,
      -
      13320  m_MemoryTypeIndex,
      -
      13321  suballocType,
      -
      13322  mapped,
      -
      13323  (allocFlags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0);
      -
      13324  VMA_HEAVY_ASSERT(pBlock->Validate());
      -
      13325  (*pAllocation)->SetUserData(m_hAllocator, pUserData);
      -
      13326  m_hAllocator->m_Budget.AddAllocation(m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex), size);
      -
      13327  if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
      -
      13328  {
      -
      13329  m_hAllocator->FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED);
      -
      13330  }
      -
      13331  if(IsCorruptionDetectionEnabled())
      -
      13332  {
      -
      13333  VkResult res = pBlock->WriteMagicValueAroundAllocation(m_hAllocator, currRequest.offset, size);
      -
      13334  VMA_ASSERT(res == VK_SUCCESS && "Couldn't map block memory to write magic value.");
      -
      13335  }
      -
      13336  return VK_SUCCESS;
      -
      13337  }
      -
      13338  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      -
      13339 }
      -
      13340 
      -
      13341 VkResult VmaBlockVector::CreateBlock(VkDeviceSize blockSize, size_t* pNewBlockIndex)
      -
      13342 {
      -
      13343  VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
      -
      13344  allocInfo.memoryTypeIndex = m_MemoryTypeIndex;
      -
      13345  allocInfo.allocationSize = blockSize;
      -
      13346 
      -
      13347 #if VMA_BUFFER_DEVICE_ADDRESS
      -
      13348  // Every standalone block can potentially contain a buffer with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT - always enable the feature.
      -
      13349  VkMemoryAllocateFlagsInfoKHR allocFlagsInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR };
      -
      13350  if(m_hAllocator->m_UseKhrBufferDeviceAddress)
      -
      13351  {
      -
      13352  allocFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
      -
      13353  VmaPnextChainPushFront(&allocInfo, &allocFlagsInfo);
      -
      13354  }
      -
      13355 #endif // #if VMA_BUFFER_DEVICE_ADDRESS
      -
      13356 
      -
      13357 #if VMA_MEMORY_PRIORITY
      -
      13358  VkMemoryPriorityAllocateInfoEXT priorityInfo = { VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT };
      -
      13359  if(m_hAllocator->m_UseExtMemoryPriority)
      -
      13360  {
      -
      13361  priorityInfo.priority = m_Priority;
      -
      13362  VmaPnextChainPushFront(&allocInfo, &priorityInfo);
      -
      13363  }
      -
      13364 #endif // #if VMA_MEMORY_PRIORITY
      -
      13365 
      -
      13366  VkDeviceMemory mem = VK_NULL_HANDLE;
      -
      13367  VkResult res = m_hAllocator->AllocateVulkanMemory(&allocInfo, &mem);
      -
      13368  if(res < 0)
      -
      13369  {
      -
      13370  return res;
      -
      13371  }
      -
      13372 
      -
      13373  // New VkDeviceMemory successfully created.
      -
      13374 
      -
      13375  // Create new Allocation for it.
      -
      13376  VmaDeviceMemoryBlock* const pBlock = vma_new(m_hAllocator, VmaDeviceMemoryBlock)(m_hAllocator);
      -
      13377  pBlock->Init(
      -
      13378  m_hAllocator,
      -
      13379  m_hParentPool,
      -
      13380  m_MemoryTypeIndex,
      -
      13381  mem,
      -
      13382  allocInfo.allocationSize,
      -
      13383  m_NextBlockId++,
      -
      13384  m_Algorithm);
      -
      13385 
      -
      13386  m_Blocks.push_back(pBlock);
      -
      13387  if(pNewBlockIndex != VMA_NULL)
      -
      13388  {
      -
      13389  *pNewBlockIndex = m_Blocks.size() - 1;
      -
      13390  }
      -
      13391 
      -
      13392  return VK_SUCCESS;
      -
      13393 }
      -
      13394 
      -
      13395 void VmaBlockVector::ApplyDefragmentationMovesCpu(
      -
      13396  class VmaBlockVectorDefragmentationContext* pDefragCtx,
      -
      13397  const VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves)
      -
      13398 {
      -
      13399  const size_t blockCount = m_Blocks.size();
      -
      13400  const bool isNonCoherent = m_hAllocator->IsMemoryTypeNonCoherent(m_MemoryTypeIndex);
      -
      13401 
      -
      13402  enum BLOCK_FLAG
      -
      13403  {
      -
      13404  BLOCK_FLAG_USED = 0x00000001,
      -
      13405  BLOCK_FLAG_MAPPED_FOR_DEFRAGMENTATION = 0x00000002,
      -
      13406  };
      +
      13252 
      +
      13253  // 3. Try to allocate from existing blocks with making other allocations lost.
      +
      13254  if(canMakeOtherLost)
      +
      13255  {
      +
      13256  uint32_t tryIndex = 0;
      +
      13257  for(; tryIndex < VMA_ALLOCATION_TRY_COUNT; ++tryIndex)
      +
      13258  {
      +
      13259  VmaDeviceMemoryBlock* pBestRequestBlock = VMA_NULL;
      +
      13260  VmaAllocationRequest bestRequest = {};
      +
      13261  VkDeviceSize bestRequestCost = VK_WHOLE_SIZE;
      +
      13262 
      +
      13263  // 1. Search existing allocations.
      + +
      13265  {
      +
      13266  // Forward order in m_Blocks - prefer blocks with smallest amount of free space.
      +
      13267  for(size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex )
      +
      13268  {
      +
      13269  VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];
      +
      13270  VMA_ASSERT(pCurrBlock);
      +
      13271  VmaAllocationRequest currRequest = {};
      +
      13272  if(pCurrBlock->m_pMetadata->CreateAllocationRequest(
      +
      13273  currentFrameIndex,
      +
      13274  m_FrameInUseCount,
      +
      13275  m_BufferImageGranularity,
      +
      13276  size,
      +
      13277  alignment,
      +
      13278  (createInfo.flags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0,
      +
      13279  suballocType,
      +
      13280  canMakeOtherLost,
      +
      13281  strategy,
      +
      13282  &currRequest))
      +
      13283  {
      +
      13284  const VkDeviceSize currRequestCost = currRequest.CalcCost();
      +
      13285  if(pBestRequestBlock == VMA_NULL ||
      +
      13286  currRequestCost < bestRequestCost)
      +
      13287  {
      +
      13288  pBestRequestBlock = pCurrBlock;
      +
      13289  bestRequest = currRequest;
      +
      13290  bestRequestCost = currRequestCost;
      +
      13291 
      +
      13292  if(bestRequestCost == 0)
      +
      13293  {
      +
      13294  break;
      +
      13295  }
      +
      13296  }
      +
      13297  }
      +
      13298  }
      +
      13299  }
      +
      13300  else // WORST_FIT, FIRST_FIT
      +
      13301  {
      +
      13302  // Backward order in m_Blocks - prefer blocks with largest amount of free space.
      +
      13303  for(size_t blockIndex = m_Blocks.size(); blockIndex--; )
      +
      13304  {
      +
      13305  VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];
      +
      13306  VMA_ASSERT(pCurrBlock);
      +
      13307  VmaAllocationRequest currRequest = {};
      +
      13308  if(pCurrBlock->m_pMetadata->CreateAllocationRequest(
      +
      13309  currentFrameIndex,
      +
      13310  m_FrameInUseCount,
      +
      13311  m_BufferImageGranularity,
      +
      13312  size,
      +
      13313  alignment,
      +
      13314  (createInfo.flags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0,
      +
      13315  suballocType,
      +
      13316  canMakeOtherLost,
      +
      13317  strategy,
      +
      13318  &currRequest))
      +
      13319  {
      +
      13320  const VkDeviceSize currRequestCost = currRequest.CalcCost();
      +
      13321  if(pBestRequestBlock == VMA_NULL ||
      +
      13322  currRequestCost < bestRequestCost ||
      + +
      13324  {
      +
      13325  pBestRequestBlock = pCurrBlock;
      +
      13326  bestRequest = currRequest;
      +
      13327  bestRequestCost = currRequestCost;
      +
      13328 
      +
      13329  if(bestRequestCost == 0 ||
      + +
      13331  {
      +
      13332  break;
      +
      13333  }
      +
      13334  }
      +
      13335  }
      +
      13336  }
      +
      13337  }
      +
      13338 
      +
      13339  if(pBestRequestBlock != VMA_NULL)
      +
      13340  {
      +
      13341  if(mapped)
      +
      13342  {
      +
      13343  VkResult res = pBestRequestBlock->Map(m_hAllocator, 1, VMA_NULL);
      +
      13344  if(res != VK_SUCCESS)
      +
      13345  {
      +
      13346  return res;
      +
      13347  }
      +
      13348  }
      +
      13349 
      +
      13350  if(pBestRequestBlock->m_pMetadata->MakeRequestedAllocationsLost(
      +
      13351  currentFrameIndex,
      +
      13352  m_FrameInUseCount,
      +
      13353  &bestRequest))
      +
      13354  {
      +
      13355  // Allocate from this pBlock.
      +
      13356  *pAllocation = m_hAllocator->m_AllocationObjectAllocator.Allocate(currentFrameIndex, isUserDataString);
      +
      13357  pBestRequestBlock->m_pMetadata->Alloc(bestRequest, suballocType, size, *pAllocation);
      +
      13358  UpdateHasEmptyBlock();
      +
      13359  (*pAllocation)->InitBlockAllocation(
      +
      13360  pBestRequestBlock,
      +
      13361  bestRequest.offset,
      +
      13362  alignment,
      +
      13363  size,
      +
      13364  m_MemoryTypeIndex,
      +
      13365  suballocType,
      +
      13366  mapped,
      +
      13367  (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0);
      +
      13368  VMA_HEAVY_ASSERT(pBestRequestBlock->Validate());
      +
      13369  VMA_DEBUG_LOG(" Returned from existing block");
      +
      13370  (*pAllocation)->SetUserData(m_hAllocator, createInfo.pUserData);
      +
      13371  m_hAllocator->m_Budget.AddAllocation(m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex), size);
      +
      13372  if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
      +
      13373  {
      +
      13374  m_hAllocator->FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED);
      +
      13375  }
      +
      13376  if(IsCorruptionDetectionEnabled())
      +
      13377  {
      +
      13378  VkResult res = pBestRequestBlock->WriteMagicValueAroundAllocation(m_hAllocator, bestRequest.offset, size);
      +
      13379  VMA_ASSERT(res == VK_SUCCESS && "Couldn't map block memory to write magic value.");
      +
      13380  }
      +
      13381  return VK_SUCCESS;
      +
      13382  }
      +
      13383  // else: Some allocations must have been touched while we are here. Next try.
      +
      13384  }
      +
      13385  else
      +
      13386  {
      +
      13387  // Could not find place in any of the blocks - break outer loop.
      +
      13388  break;
      +
      13389  }
      +
      13390  }
      +
      13391  /* Maximum number of tries exceeded - a very unlike event when many other
      +
      13392  threads are simultaneously touching allocations making it impossible to make
      +
      13393  lost at the same time as we try to allocate. */
      +
      13394  if(tryIndex == VMA_ALLOCATION_TRY_COUNT)
      +
      13395  {
      +
      13396  return VK_ERROR_TOO_MANY_OBJECTS;
      +
      13397  }
      +
      13398  }
      +
      13399 
      +
      13400  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      +
      13401 }
      +
      13402 
      +
      13403 void VmaBlockVector::Free(
      +
      13404  const VmaAllocation hAllocation)
      +
      13405 {
      +
      13406  VmaDeviceMemoryBlock* pBlockToDelete = VMA_NULL;
      13407 
      -
      13408  struct BlockInfo
      +
      13408  bool budgetExceeded = false;
      13409  {
      -
      13410  uint32_t flags;
      -
      13411  void* pMappedData;
      -
      13412  };
      -
      13413  VmaVector< BlockInfo, VmaStlAllocator<BlockInfo> >
      -
      13414  blockInfo(blockCount, BlockInfo(), VmaStlAllocator<BlockInfo>(m_hAllocator->GetAllocationCallbacks()));
      -
      13415  memset(blockInfo.data(), 0, blockCount * sizeof(BlockInfo));
      -
      13416 
      -
      13417  // Go over all moves. Mark blocks that are used with BLOCK_FLAG_USED.
      -
      13418  const size_t moveCount = moves.size();
      -
      13419  for(size_t moveIndex = 0; moveIndex < moveCount; ++moveIndex)
      -
      13420  {
      -
      13421  const VmaDefragmentationMove& move = moves[moveIndex];
      -
      13422  blockInfo[move.srcBlockIndex].flags |= BLOCK_FLAG_USED;
      -
      13423  blockInfo[move.dstBlockIndex].flags |= BLOCK_FLAG_USED;
      -
      13424  }
      -
      13425 
      -
      13426  VMA_ASSERT(pDefragCtx->res == VK_SUCCESS);
      +
      13410  const uint32_t heapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex);
      +
      13411  VmaBudget heapBudget = {};
      +
      13412  m_hAllocator->GetBudget(&heapBudget, heapIndex, 1);
      +
      13413  budgetExceeded = heapBudget.usage >= heapBudget.budget;
      +
      13414  }
      +
      13415 
      +
      13416  // Scope for lock.
      +
      13417  {
      +
      13418  VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
      +
      13419 
      +
      13420  VmaDeviceMemoryBlock* pBlock = hAllocation->GetBlock();
      +
      13421 
      +
      13422  if(IsCorruptionDetectionEnabled())
      +
      13423  {
      +
      13424  VkResult res = pBlock->ValidateMagicValueAroundAllocation(m_hAllocator, hAllocation->GetOffset(), hAllocation->GetSize());
      +
      13425  VMA_ASSERT(res == VK_SUCCESS && "Couldn't map block memory to validate magic value.");
      +
      13426  }
      13427 
      -
      13428  // Go over all blocks. Get mapped pointer or map if necessary.
      -
      13429  for(size_t blockIndex = 0; pDefragCtx->res == VK_SUCCESS && blockIndex < blockCount; ++blockIndex)
      -
      13430  {
      -
      13431  BlockInfo& currBlockInfo = blockInfo[blockIndex];
      -
      13432  VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex];
      -
      13433  if((currBlockInfo.flags & BLOCK_FLAG_USED) != 0)
      -
      13434  {
      -
      13435  currBlockInfo.pMappedData = pBlock->GetMappedData();
      -
      13436  // It is not originally mapped - map it.
      -
      13437  if(currBlockInfo.pMappedData == VMA_NULL)
      -
      13438  {
      -
      13439  pDefragCtx->res = pBlock->Map(m_hAllocator, 1, &currBlockInfo.pMappedData);
      -
      13440  if(pDefragCtx->res == VK_SUCCESS)
      -
      13441  {
      -
      13442  currBlockInfo.flags |= BLOCK_FLAG_MAPPED_FOR_DEFRAGMENTATION;
      -
      13443  }
      -
      13444  }
      -
      13445  }
      -
      13446  }
      -
      13447 
      -
      13448  // Go over all moves. Do actual data transfer.
      -
      13449  if(pDefragCtx->res == VK_SUCCESS)
      -
      13450  {
      -
      13451  const VkDeviceSize nonCoherentAtomSize = m_hAllocator->m_PhysicalDeviceProperties.limits.nonCoherentAtomSize;
      -
      13452  VkMappedMemoryRange memRange = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE };
      -
      13453 
      -
      13454  for(size_t moveIndex = 0; moveIndex < moveCount; ++moveIndex)
      -
      13455  {
      -
      13456  const VmaDefragmentationMove& move = moves[moveIndex];
      -
      13457 
      -
      13458  const BlockInfo& srcBlockInfo = blockInfo[move.srcBlockIndex];
      -
      13459  const BlockInfo& dstBlockInfo = blockInfo[move.dstBlockIndex];
      -
      13460 
      -
      13461  VMA_ASSERT(srcBlockInfo.pMappedData && dstBlockInfo.pMappedData);
      -
      13462 
      -
      13463  // Invalidate source.
      -
      13464  if(isNonCoherent)
      -
      13465  {
      -
      13466  VmaDeviceMemoryBlock* const pSrcBlock = m_Blocks[move.srcBlockIndex];
      -
      13467  memRange.memory = pSrcBlock->GetDeviceMemory();
      -
      13468  memRange.offset = VmaAlignDown(move.srcOffset, nonCoherentAtomSize);
      -
      13469  memRange.size = VMA_MIN(
      -
      13470  VmaAlignUp(move.size + (move.srcOffset - memRange.offset), nonCoherentAtomSize),
      -
      13471  pSrcBlock->m_pMetadata->GetSize() - memRange.offset);
      -
      13472  (*m_hAllocator->GetVulkanFunctions().vkInvalidateMappedMemoryRanges)(m_hAllocator->m_hDevice, 1, &memRange);
      -
      13473  }
      -
      13474 
      -
      13475  // THE PLACE WHERE ACTUAL DATA COPY HAPPENS.
      -
      13476  memmove(
      -
      13477  reinterpret_cast<char*>(dstBlockInfo.pMappedData) + move.dstOffset,
      -
      13478  reinterpret_cast<char*>(srcBlockInfo.pMappedData) + move.srcOffset,
      -
      13479  static_cast<size_t>(move.size));
      -
      13480 
      -
      13481  if(IsCorruptionDetectionEnabled())
      -
      13482  {
      -
      13483  VmaWriteMagicValue(dstBlockInfo.pMappedData, move.dstOffset - VMA_DEBUG_MARGIN);
      -
      13484  VmaWriteMagicValue(dstBlockInfo.pMappedData, move.dstOffset + move.size);
      -
      13485  }
      -
      13486 
      -
      13487  // Flush destination.
      -
      13488  if(isNonCoherent)
      -
      13489  {
      -
      13490  VmaDeviceMemoryBlock* const pDstBlock = m_Blocks[move.dstBlockIndex];
      -
      13491  memRange.memory = pDstBlock->GetDeviceMemory();
      -
      13492  memRange.offset = VmaAlignDown(move.dstOffset, nonCoherentAtomSize);
      -
      13493  memRange.size = VMA_MIN(
      -
      13494  VmaAlignUp(move.size + (move.dstOffset - memRange.offset), nonCoherentAtomSize),
      -
      13495  pDstBlock->m_pMetadata->GetSize() - memRange.offset);
      -
      13496  (*m_hAllocator->GetVulkanFunctions().vkFlushMappedMemoryRanges)(m_hAllocator->m_hDevice, 1, &memRange);
      -
      13497  }
      +
      13428  if(hAllocation->IsPersistentMap())
      +
      13429  {
      +
      13430  pBlock->Unmap(m_hAllocator, 1);
      +
      13431  }
      +
      13432 
      +
      13433  pBlock->m_pMetadata->Free(hAllocation);
      +
      13434  VMA_HEAVY_ASSERT(pBlock->Validate());
      +
      13435 
      +
      13436  VMA_DEBUG_LOG(" Freed from MemoryTypeIndex=%u", m_MemoryTypeIndex);
      +
      13437 
      +
      13438  const bool canDeleteBlock = m_Blocks.size() > m_MinBlockCount;
      +
      13439  // pBlock became empty after this deallocation.
      +
      13440  if(pBlock->m_pMetadata->IsEmpty())
      +
      13441  {
      +
      13442  // Already has empty block. We don't want to have two, so delete this one.
      +
      13443  if((m_HasEmptyBlock || budgetExceeded) && canDeleteBlock)
      +
      13444  {
      +
      13445  pBlockToDelete = pBlock;
      +
      13446  Remove(pBlock);
      +
      13447  }
      +
      13448  // else: We now have an empty block - leave it.
      +
      13449  }
      +
      13450  // pBlock didn't become empty, but we have another empty block - find and free that one.
      +
      13451  // (This is optional, heuristics.)
      +
      13452  else if(m_HasEmptyBlock && canDeleteBlock)
      +
      13453  {
      +
      13454  VmaDeviceMemoryBlock* pLastBlock = m_Blocks.back();
      +
      13455  if(pLastBlock->m_pMetadata->IsEmpty())
      +
      13456  {
      +
      13457  pBlockToDelete = pLastBlock;
      +
      13458  m_Blocks.pop_back();
      +
      13459  }
      +
      13460  }
      +
      13461 
      +
      13462  UpdateHasEmptyBlock();
      +
      13463  IncrementallySortBlocks();
      +
      13464  }
      +
      13465 
      +
      13466  // Destruction of a free block. Deferred until this point, outside of mutex
      +
      13467  // lock, for performance reason.
      +
      13468  if(pBlockToDelete != VMA_NULL)
      +
      13469  {
      +
      13470  VMA_DEBUG_LOG(" Deleted empty block");
      +
      13471  pBlockToDelete->Destroy(m_hAllocator);
      +
      13472  vma_delete(m_hAllocator, pBlockToDelete);
      +
      13473  }
      +
      13474 }
      +
      13475 
      +
      13476 VkDeviceSize VmaBlockVector::CalcMaxBlockSize() const
      +
      13477 {
      +
      13478  VkDeviceSize result = 0;
      +
      13479  for(size_t i = m_Blocks.size(); i--; )
      +
      13480  {
      +
      13481  result = VMA_MAX(result, m_Blocks[i]->m_pMetadata->GetSize());
      +
      13482  if(result >= m_PreferredBlockSize)
      +
      13483  {
      +
      13484  break;
      +
      13485  }
      +
      13486  }
      +
      13487  return result;
      +
      13488 }
      +
      13489 
      +
      13490 void VmaBlockVector::Remove(VmaDeviceMemoryBlock* pBlock)
      +
      13491 {
      +
      13492  for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
      +
      13493  {
      +
      13494  if(m_Blocks[blockIndex] == pBlock)
      +
      13495  {
      +
      13496  VmaVectorRemove(m_Blocks, blockIndex);
      +
      13497  return;
      13498  }
      13499  }
      -
      13500 
      -
      13501  // Go over all blocks in reverse order. Unmap those that were mapped just for defragmentation.
      -
      13502  // Regardless of pCtx->res == VK_SUCCESS.
      -
      13503  for(size_t blockIndex = blockCount; blockIndex--; )
      -
      13504  {
      -
      13505  const BlockInfo& currBlockInfo = blockInfo[blockIndex];
      -
      13506  if((currBlockInfo.flags & BLOCK_FLAG_MAPPED_FOR_DEFRAGMENTATION) != 0)
      -
      13507  {
      -
      13508  VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex];
      -
      13509  pBlock->Unmap(m_hAllocator, 1);
      -
      13510  }
      -
      13511  }
      -
      13512 }
      -
      13513 
      -
      13514 void VmaBlockVector::ApplyDefragmentationMovesGpu(
      -
      13515  class VmaBlockVectorDefragmentationContext* pDefragCtx,
      -
      13516  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
      -
      13517  VkCommandBuffer commandBuffer)
      -
      13518 {
      -
      13519  const size_t blockCount = m_Blocks.size();
      -
      13520 
      -
      13521  pDefragCtx->blockContexts.resize(blockCount);
      -
      13522  memset(pDefragCtx->blockContexts.data(), 0, blockCount * sizeof(VmaBlockDefragmentationContext));
      -
      13523 
      -
      13524  // Go over all moves. Mark blocks that are used with BLOCK_FLAG_USED.
      -
      13525  const size_t moveCount = moves.size();
      -
      13526  for(size_t moveIndex = 0; moveIndex < moveCount; ++moveIndex)
      -
      13527  {
      -
      13528  const VmaDefragmentationMove& move = moves[moveIndex];
      -
      13529 
      -
      13530  //if(move.type == VMA_ALLOCATION_TYPE_UNKNOWN)
      -
      13531  {
      -
      13532  // Old school move still require us to map the whole block
      -
      13533  pDefragCtx->blockContexts[move.srcBlockIndex].flags |= VmaBlockDefragmentationContext::BLOCK_FLAG_USED;
      -
      13534  pDefragCtx->blockContexts[move.dstBlockIndex].flags |= VmaBlockDefragmentationContext::BLOCK_FLAG_USED;
      -
      13535  }
      -
      13536  }
      -
      13537 
      -
      13538  VMA_ASSERT(pDefragCtx->res == VK_SUCCESS);
      -
      13539 
      -
      13540  // Go over all blocks. Create and bind buffer for whole block if necessary.
      -
      13541  {
      -
      13542  VkBufferCreateInfo bufCreateInfo;
      -
      13543  VmaFillGpuDefragmentationBufferCreateInfo(bufCreateInfo);
      -
      13544 
      -
      13545  for(size_t blockIndex = 0; pDefragCtx->res == VK_SUCCESS && blockIndex < blockCount; ++blockIndex)
      -
      13546  {
      -
      13547  VmaBlockDefragmentationContext& currBlockCtx = pDefragCtx->blockContexts[blockIndex];
      -
      13548  VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex];
      -
      13549  if((currBlockCtx.flags & VmaBlockDefragmentationContext::BLOCK_FLAG_USED) != 0)
      -
      13550  {
      -
      13551  bufCreateInfo.size = pBlock->m_pMetadata->GetSize();
      -
      13552  pDefragCtx->res = (*m_hAllocator->GetVulkanFunctions().vkCreateBuffer)(
      -
      13553  m_hAllocator->m_hDevice, &bufCreateInfo, m_hAllocator->GetAllocationCallbacks(), &currBlockCtx.hBuffer);
      -
      13554  if(pDefragCtx->res == VK_SUCCESS)
      -
      13555  {
      -
      13556  pDefragCtx->res = (*m_hAllocator->GetVulkanFunctions().vkBindBufferMemory)(
      -
      13557  m_hAllocator->m_hDevice, currBlockCtx.hBuffer, pBlock->GetDeviceMemory(), 0);
      -
      13558  }
      -
      13559  }
      -
      13560  }
      -
      13561  }
      -
      13562 
      -
      13563  // Go over all moves. Post data transfer commands to command buffer.
      -
      13564  if(pDefragCtx->res == VK_SUCCESS)
      -
      13565  {
      -
      13566  for(size_t moveIndex = 0; moveIndex < moveCount; ++moveIndex)
      -
      13567  {
      -
      13568  const VmaDefragmentationMove& move = moves[moveIndex];
      -
      13569 
      -
      13570  const VmaBlockDefragmentationContext& srcBlockCtx = pDefragCtx->blockContexts[move.srcBlockIndex];
      -
      13571  const VmaBlockDefragmentationContext& dstBlockCtx = pDefragCtx->blockContexts[move.dstBlockIndex];
      -
      13572 
      -
      13573  VMA_ASSERT(srcBlockCtx.hBuffer && dstBlockCtx.hBuffer);
      -
      13574 
      -
      13575  VkBufferCopy region = {
      -
      13576  move.srcOffset,
      -
      13577  move.dstOffset,
      -
      13578  move.size };
      -
      13579  (*m_hAllocator->GetVulkanFunctions().vkCmdCopyBuffer)(
      -
      13580  commandBuffer, srcBlockCtx.hBuffer, dstBlockCtx.hBuffer, 1, &region);
      -
      13581  }
      -
      13582  }
      -
      13583 
      -
      13584  // Save buffers to defrag context for later destruction.
      -
      13585  if(pDefragCtx->res == VK_SUCCESS && moveCount > 0)
      -
      13586  {
      -
      13587  pDefragCtx->res = VK_NOT_READY;
      -
      13588  }
      -
      13589 }
      -
      13590 
      -
      13591 void VmaBlockVector::FreeEmptyBlocks(VmaDefragmentationStats* pDefragmentationStats)
      -
      13592 {
      -
      13593  for(size_t blockIndex = m_Blocks.size(); blockIndex--; )
      -
      13594  {
      -
      13595  VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex];
      -
      13596  if(pBlock->m_pMetadata->IsEmpty())
      -
      13597  {
      -
      13598  if(m_Blocks.size() > m_MinBlockCount)
      -
      13599  {
      -
      13600  if(pDefragmentationStats != VMA_NULL)
      -
      13601  {
      -
      13602  ++pDefragmentationStats->deviceMemoryBlocksFreed;
      -
      13603  pDefragmentationStats->bytesFreed += pBlock->m_pMetadata->GetSize();
      -
      13604  }
      -
      13605 
      -
      13606  VmaVectorRemove(m_Blocks, blockIndex);
      -
      13607  pBlock->Destroy(m_hAllocator);
      -
      13608  vma_delete(m_hAllocator, pBlock);
      -
      13609  }
      -
      13610  else
      -
      13611  {
      -
      13612  break;
      -
      13613  }
      -
      13614  }
      -
      13615  }
      -
      13616  UpdateHasEmptyBlock();
      -
      13617 }
      -
      13618 
      -
      13619 void VmaBlockVector::UpdateHasEmptyBlock()
      -
      13620 {
      -
      13621  m_HasEmptyBlock = false;
      -
      13622  for(size_t index = 0, count = m_Blocks.size(); index < count; ++index)
      -
      13623  {
      -
      13624  VmaDeviceMemoryBlock* const pBlock = m_Blocks[index];
      -
      13625  if(pBlock->m_pMetadata->IsEmpty())
      -
      13626  {
      -
      13627  m_HasEmptyBlock = true;
      -
      13628  break;
      -
      13629  }
      -
      13630  }
      -
      13631 }
      -
      13632 
      -
      13633 #if VMA_STATS_STRING_ENABLED
      -
      13634 
      -
      13635 void VmaBlockVector::PrintDetailedMap(class VmaJsonWriter& json)
      -
      13636 {
      -
      13637  VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex);
      -
      13638 
      -
      13639  json.BeginObject();
      -
      13640 
      -
      13641  if(IsCustomPool())
      -
      13642  {
      -
      13643  const char* poolName = m_hParentPool->GetName();
      -
      13644  if(poolName != VMA_NULL && poolName[0] != '\0')
      -
      13645  {
      -
      13646  json.WriteString("Name");
      -
      13647  json.WriteString(poolName);
      -
      13648  }
      +
      13500  VMA_ASSERT(0);
      +
      13501 }
      +
      13502 
      +
      13503 void VmaBlockVector::IncrementallySortBlocks()
      +
      13504 {
      +
      13505  if(m_Algorithm != VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT)
      +
      13506  {
      +
      13507  // Bubble sort only until first swap.
      +
      13508  for(size_t i = 1; i < m_Blocks.size(); ++i)
      +
      13509  {
      +
      13510  if(m_Blocks[i - 1]->m_pMetadata->GetSumFreeSize() > m_Blocks[i]->m_pMetadata->GetSumFreeSize())
      +
      13511  {
      +
      13512  VMA_SWAP(m_Blocks[i - 1], m_Blocks[i]);
      +
      13513  return;
      +
      13514  }
      +
      13515  }
      +
      13516  }
      +
      13517 }
      +
      13518 
      +
      13519 VkResult VmaBlockVector::AllocateFromBlock(
      +
      13520  VmaDeviceMemoryBlock* pBlock,
      +
      13521  uint32_t currentFrameIndex,
      +
      13522  VkDeviceSize size,
      +
      13523  VkDeviceSize alignment,
      +
      13524  VmaAllocationCreateFlags allocFlags,
      +
      13525  void* pUserData,
      +
      13526  VmaSuballocationType suballocType,
      +
      13527  uint32_t strategy,
      +
      13528  VmaAllocation* pAllocation)
      +
      13529 {
      +
      13530  VMA_ASSERT((allocFlags & VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT) == 0);
      +
      13531  const bool isUpperAddress = (allocFlags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0;
      +
      13532  const bool mapped = (allocFlags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0;
      +
      13533  const bool isUserDataString = (allocFlags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0;
      +
      13534 
      +
      13535  VmaAllocationRequest currRequest = {};
      +
      13536  if(pBlock->m_pMetadata->CreateAllocationRequest(
      +
      13537  currentFrameIndex,
      +
      13538  m_FrameInUseCount,
      +
      13539  m_BufferImageGranularity,
      +
      13540  size,
      +
      13541  alignment,
      +
      13542  isUpperAddress,
      +
      13543  suballocType,
      +
      13544  false, // canMakeOtherLost
      +
      13545  strategy,
      +
      13546  &currRequest))
      +
      13547  {
      +
      13548  // Allocate from pCurrBlock.
      +
      13549  VMA_ASSERT(currRequest.itemsToMakeLostCount == 0);
      +
      13550 
      +
      13551  if(mapped)
      +
      13552  {
      +
      13553  VkResult res = pBlock->Map(m_hAllocator, 1, VMA_NULL);
      +
      13554  if(res != VK_SUCCESS)
      +
      13555  {
      +
      13556  return res;
      +
      13557  }
      +
      13558  }
      +
      13559 
      +
      13560  *pAllocation = m_hAllocator->m_AllocationObjectAllocator.Allocate(currentFrameIndex, isUserDataString);
      +
      13561  pBlock->m_pMetadata->Alloc(currRequest, suballocType, size, *pAllocation);
      +
      13562  UpdateHasEmptyBlock();
      +
      13563  (*pAllocation)->InitBlockAllocation(
      +
      13564  pBlock,
      +
      13565  currRequest.offset,
      +
      13566  alignment,
      +
      13567  size,
      +
      13568  m_MemoryTypeIndex,
      +
      13569  suballocType,
      +
      13570  mapped,
      +
      13571  (allocFlags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0);
      +
      13572  VMA_HEAVY_ASSERT(pBlock->Validate());
      +
      13573  (*pAllocation)->SetUserData(m_hAllocator, pUserData);
      +
      13574  m_hAllocator->m_Budget.AddAllocation(m_hAllocator->MemoryTypeIndexToHeapIndex(m_MemoryTypeIndex), size);
      +
      13575  if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
      +
      13576  {
      +
      13577  m_hAllocator->FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED);
      +
      13578  }
      +
      13579  if(IsCorruptionDetectionEnabled())
      +
      13580  {
      +
      13581  VkResult res = pBlock->WriteMagicValueAroundAllocation(m_hAllocator, currRequest.offset, size);
      +
      13582  VMA_ASSERT(res == VK_SUCCESS && "Couldn't map block memory to write magic value.");
      +
      13583  }
      +
      13584  return VK_SUCCESS;
      +
      13585  }
      +
      13586  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      +
      13587 }
      +
      13588 
      +
      13589 VkResult VmaBlockVector::CreateBlock(VkDeviceSize blockSize, size_t* pNewBlockIndex)
      +
      13590 {
      +
      13591  VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
      +
      13592  allocInfo.memoryTypeIndex = m_MemoryTypeIndex;
      +
      13593  allocInfo.allocationSize = blockSize;
      +
      13594 
      +
      13595 #if VMA_BUFFER_DEVICE_ADDRESS
      +
      13596  // Every standalone block can potentially contain a buffer with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT - always enable the feature.
      +
      13597  VkMemoryAllocateFlagsInfoKHR allocFlagsInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR };
      +
      13598  if(m_hAllocator->m_UseKhrBufferDeviceAddress)
      +
      13599  {
      +
      13600  allocFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
      +
      13601  VmaPnextChainPushFront(&allocInfo, &allocFlagsInfo);
      +
      13602  }
      +
      13603 #endif // #if VMA_BUFFER_DEVICE_ADDRESS
      +
      13604 
      +
      13605 #if VMA_MEMORY_PRIORITY
      +
      13606  VkMemoryPriorityAllocateInfoEXT priorityInfo = { VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT };
      +
      13607  if(m_hAllocator->m_UseExtMemoryPriority)
      +
      13608  {
      +
      13609  priorityInfo.priority = m_Priority;
      +
      13610  VmaPnextChainPushFront(&allocInfo, &priorityInfo);
      +
      13611  }
      +
      13612 #endif // #if VMA_MEMORY_PRIORITY
      +
      13613 
      +
      13614  VkDeviceMemory mem = VK_NULL_HANDLE;
      +
      13615  VkResult res = m_hAllocator->AllocateVulkanMemory(&allocInfo, &mem);
      +
      13616  if(res < 0)
      +
      13617  {
      +
      13618  return res;
      +
      13619  }
      +
      13620 
      +
      13621  // New VkDeviceMemory successfully created.
      +
      13622 
      +
      13623  // Create new Allocation for it.
      +
      13624  VmaDeviceMemoryBlock* const pBlock = vma_new(m_hAllocator, VmaDeviceMemoryBlock)(m_hAllocator);
      +
      13625  pBlock->Init(
      +
      13626  m_hAllocator,
      +
      13627  m_hParentPool,
      +
      13628  m_MemoryTypeIndex,
      +
      13629  mem,
      +
      13630  allocInfo.allocationSize,
      +
      13631  m_NextBlockId++,
      +
      13632  m_Algorithm);
      +
      13633 
      +
      13634  m_Blocks.push_back(pBlock);
      +
      13635  if(pNewBlockIndex != VMA_NULL)
      +
      13636  {
      +
      13637  *pNewBlockIndex = m_Blocks.size() - 1;
      +
      13638  }
      +
      13639 
      +
      13640  return VK_SUCCESS;
      +
      13641 }
      +
      13642 
      +
      13643 void VmaBlockVector::ApplyDefragmentationMovesCpu(
      +
      13644  class VmaBlockVectorDefragmentationContext* pDefragCtx,
      +
      13645  const VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves)
      +
      13646 {
      +
      13647  const size_t blockCount = m_Blocks.size();
      +
      13648  const bool isNonCoherent = m_hAllocator->IsMemoryTypeNonCoherent(m_MemoryTypeIndex);
      13649 
      -
      13650  json.WriteString("MemoryTypeIndex");
      -
      13651  json.WriteNumber(m_MemoryTypeIndex);
      -
      13652 
      -
      13653  json.WriteString("BlockSize");
      -
      13654  json.WriteNumber(m_PreferredBlockSize);
      +
      13650  enum BLOCK_FLAG
      +
      13651  {
      +
      13652  BLOCK_FLAG_USED = 0x00000001,
      +
      13653  BLOCK_FLAG_MAPPED_FOR_DEFRAGMENTATION = 0x00000002,
      +
      13654  };
      13655 
      -
      13656  json.WriteString("BlockCount");
      -
      13657  json.BeginObject(true);
      -
      13658  if(m_MinBlockCount > 0)
      -
      13659  {
      -
      13660  json.WriteString("Min");
      -
      13661  json.WriteNumber((uint64_t)m_MinBlockCount);
      -
      13662  }
      -
      13663  if(m_MaxBlockCount < SIZE_MAX)
      -
      13664  {
      -
      13665  json.WriteString("Max");
      -
      13666  json.WriteNumber((uint64_t)m_MaxBlockCount);
      -
      13667  }
      -
      13668  json.WriteString("Cur");
      -
      13669  json.WriteNumber((uint64_t)m_Blocks.size());
      -
      13670  json.EndObject();
      -
      13671 
      -
      13672  if(m_FrameInUseCount > 0)
      -
      13673  {
      -
      13674  json.WriteString("FrameInUseCount");
      -
      13675  json.WriteNumber(m_FrameInUseCount);
      -
      13676  }
      -
      13677 
      -
      13678  if(m_Algorithm != 0)
      -
      13679  {
      -
      13680  json.WriteString("Algorithm");
      -
      13681  json.WriteString(VmaAlgorithmToStr(m_Algorithm));
      -
      13682  }
      -
      13683  }
      -
      13684  else
      -
      13685  {
      -
      13686  json.WriteString("PreferredBlockSize");
      -
      13687  json.WriteNumber(m_PreferredBlockSize);
      -
      13688  }
      -
      13689 
      -
      13690  json.WriteString("Blocks");
      -
      13691  json.BeginObject();
      -
      13692  for(size_t i = 0; i < m_Blocks.size(); ++i)
      -
      13693  {
      -
      13694  json.BeginString();
      -
      13695  json.ContinueString(m_Blocks[i]->GetId());
      -
      13696  json.EndString();
      -
      13697 
      -
      13698  m_Blocks[i]->m_pMetadata->PrintDetailedMap(json);
      -
      13699  }
      -
      13700  json.EndObject();
      +
      13656  struct BlockInfo
      +
      13657  {
      +
      13658  uint32_t flags;
      +
      13659  void* pMappedData;
      +
      13660  };
      +
      13661  VmaVector< BlockInfo, VmaStlAllocator<BlockInfo> >
      +
      13662  blockInfo(blockCount, BlockInfo(), VmaStlAllocator<BlockInfo>(m_hAllocator->GetAllocationCallbacks()));
      +
      13663  memset(blockInfo.data(), 0, blockCount * sizeof(BlockInfo));
      +
      13664 
      +
      13665  // Go over all moves. Mark blocks that are used with BLOCK_FLAG_USED.
      +
      13666  const size_t moveCount = moves.size();
      +
      13667  for(size_t moveIndex = 0; moveIndex < moveCount; ++moveIndex)
      +
      13668  {
      +
      13669  const VmaDefragmentationMove& move = moves[moveIndex];
      +
      13670  blockInfo[move.srcBlockIndex].flags |= BLOCK_FLAG_USED;
      +
      13671  blockInfo[move.dstBlockIndex].flags |= BLOCK_FLAG_USED;
      +
      13672  }
      +
      13673 
      +
      13674  VMA_ASSERT(pDefragCtx->res == VK_SUCCESS);
      +
      13675 
      +
      13676  // Go over all blocks. Get mapped pointer or map if necessary.
      +
      13677  for(size_t blockIndex = 0; pDefragCtx->res == VK_SUCCESS && blockIndex < blockCount; ++blockIndex)
      +
      13678  {
      +
      13679  BlockInfo& currBlockInfo = blockInfo[blockIndex];
      +
      13680  VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex];
      +
      13681  if((currBlockInfo.flags & BLOCK_FLAG_USED) != 0)
      +
      13682  {
      +
      13683  currBlockInfo.pMappedData = pBlock->GetMappedData();
      +
      13684  // It is not originally mapped - map it.
      +
      13685  if(currBlockInfo.pMappedData == VMA_NULL)
      +
      13686  {
      +
      13687  pDefragCtx->res = pBlock->Map(m_hAllocator, 1, &currBlockInfo.pMappedData);
      +
      13688  if(pDefragCtx->res == VK_SUCCESS)
      +
      13689  {
      +
      13690  currBlockInfo.flags |= BLOCK_FLAG_MAPPED_FOR_DEFRAGMENTATION;
      +
      13691  }
      +
      13692  }
      +
      13693  }
      +
      13694  }
      +
      13695 
      +
      13696  // Go over all moves. Do actual data transfer.
      +
      13697  if(pDefragCtx->res == VK_SUCCESS)
      +
      13698  {
      +
      13699  const VkDeviceSize nonCoherentAtomSize = m_hAllocator->m_PhysicalDeviceProperties.limits.nonCoherentAtomSize;
      +
      13700  VkMappedMemoryRange memRange = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE };
      13701 
      -
      13702  json.EndObject();
      -
      13703 }
      -
      13704 
      -
      13705 #endif // #if VMA_STATS_STRING_ENABLED
      -
      13706 
      -
      13707 void VmaBlockVector::Defragment(
      -
      13708  class VmaBlockVectorDefragmentationContext* pCtx,
      - -
      13710  VkDeviceSize& maxCpuBytesToMove, uint32_t& maxCpuAllocationsToMove,
      -
      13711  VkDeviceSize& maxGpuBytesToMove, uint32_t& maxGpuAllocationsToMove,
      -
      13712  VkCommandBuffer commandBuffer)
      -
      13713 {
      -
      13714  pCtx->res = VK_SUCCESS;
      -
      13715 
      -
      13716  const VkMemoryPropertyFlags memPropFlags =
      -
      13717  m_hAllocator->m_MemProps.memoryTypes[m_MemoryTypeIndex].propertyFlags;
      -
      13718  const bool isHostVisible = (memPropFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0;
      -
      13719 
      -
      13720  const bool canDefragmentOnCpu = maxCpuBytesToMove > 0 && maxCpuAllocationsToMove > 0 &&
      -
      13721  isHostVisible;
      -
      13722  const bool canDefragmentOnGpu = maxGpuBytesToMove > 0 && maxGpuAllocationsToMove > 0 &&
      -
      13723  !IsCorruptionDetectionEnabled() &&
      -
      13724  ((1u << m_MemoryTypeIndex) & m_hAllocator->GetGpuDefragmentationMemoryTypeBits()) != 0;
      -
      13725 
      -
      13726  // There are options to defragment this memory type.
      -
      13727  if(canDefragmentOnCpu || canDefragmentOnGpu)
      -
      13728  {
      -
      13729  bool defragmentOnGpu;
      -
      13730  // There is only one option to defragment this memory type.
      -
      13731  if(canDefragmentOnGpu != canDefragmentOnCpu)
      -
      13732  {
      -
      13733  defragmentOnGpu = canDefragmentOnGpu;
      -
      13734  }
      -
      13735  // Both options are available: Heuristics to choose the best one.
      -
      13736  else
      -
      13737  {
      -
      13738  defragmentOnGpu = (memPropFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0 ||
      -
      13739  m_hAllocator->IsIntegratedGpu();
      -
      13740  }
      -
      13741 
      -
      13742  bool overlappingMoveSupported = !defragmentOnGpu;
      -
      13743 
      -
      13744  if(m_hAllocator->m_UseMutex)
      -
      13745  {
      - -
      13747  {
      -
      13748  if(!m_Mutex.TryLockWrite())
      -
      13749  {
      -
      13750  pCtx->res = VK_ERROR_INITIALIZATION_FAILED;
      -
      13751  return;
      -
      13752  }
      -
      13753  }
      -
      13754  else
      -
      13755  {
      -
      13756  m_Mutex.LockWrite();
      -
      13757  pCtx->mutexLocked = true;
      -
      13758  }
      -
      13759  }
      -
      13760 
      -
      13761  pCtx->Begin(overlappingMoveSupported, flags);
      -
      13762 
      -
      13763  // Defragment.
      -
      13764 
      -
      13765  const VkDeviceSize maxBytesToMove = defragmentOnGpu ? maxGpuBytesToMove : maxCpuBytesToMove;
      -
      13766  const uint32_t maxAllocationsToMove = defragmentOnGpu ? maxGpuAllocationsToMove : maxCpuAllocationsToMove;
      -
      13767  pCtx->res = pCtx->GetAlgorithm()->Defragment(pCtx->defragmentationMoves, maxBytesToMove, maxAllocationsToMove, flags);
      +
      13702  for(size_t moveIndex = 0; moveIndex < moveCount; ++moveIndex)
      +
      13703  {
      +
      13704  const VmaDefragmentationMove& move = moves[moveIndex];
      +
      13705 
      +
      13706  const BlockInfo& srcBlockInfo = blockInfo[move.srcBlockIndex];
      +
      13707  const BlockInfo& dstBlockInfo = blockInfo[move.dstBlockIndex];
      +
      13708 
      +
      13709  VMA_ASSERT(srcBlockInfo.pMappedData && dstBlockInfo.pMappedData);
      +
      13710 
      +
      13711  // Invalidate source.
      +
      13712  if(isNonCoherent)
      +
      13713  {
      +
      13714  VmaDeviceMemoryBlock* const pSrcBlock = m_Blocks[move.srcBlockIndex];
      +
      13715  memRange.memory = pSrcBlock->GetDeviceMemory();
      +
      13716  memRange.offset = VmaAlignDown(move.srcOffset, nonCoherentAtomSize);
      +
      13717  memRange.size = VMA_MIN(
      +
      13718  VmaAlignUp(move.size + (move.srcOffset - memRange.offset), nonCoherentAtomSize),
      +
      13719  pSrcBlock->m_pMetadata->GetSize() - memRange.offset);
      +
      13720  (*m_hAllocator->GetVulkanFunctions().vkInvalidateMappedMemoryRanges)(m_hAllocator->m_hDevice, 1, &memRange);
      +
      13721  }
      +
      13722 
      +
      13723  // THE PLACE WHERE ACTUAL DATA COPY HAPPENS.
      +
      13724  memmove(
      +
      13725  reinterpret_cast<char*>(dstBlockInfo.pMappedData) + move.dstOffset,
      +
      13726  reinterpret_cast<char*>(srcBlockInfo.pMappedData) + move.srcOffset,
      +
      13727  static_cast<size_t>(move.size));
      +
      13728 
      +
      13729  if(IsCorruptionDetectionEnabled())
      +
      13730  {
      +
      13731  VmaWriteMagicValue(dstBlockInfo.pMappedData, move.dstOffset - VMA_DEBUG_MARGIN);
      +
      13732  VmaWriteMagicValue(dstBlockInfo.pMappedData, move.dstOffset + move.size);
      +
      13733  }
      +
      13734 
      +
      13735  // Flush destination.
      +
      13736  if(isNonCoherent)
      +
      13737  {
      +
      13738  VmaDeviceMemoryBlock* const pDstBlock = m_Blocks[move.dstBlockIndex];
      +
      13739  memRange.memory = pDstBlock->GetDeviceMemory();
      +
      13740  memRange.offset = VmaAlignDown(move.dstOffset, nonCoherentAtomSize);
      +
      13741  memRange.size = VMA_MIN(
      +
      13742  VmaAlignUp(move.size + (move.dstOffset - memRange.offset), nonCoherentAtomSize),
      +
      13743  pDstBlock->m_pMetadata->GetSize() - memRange.offset);
      +
      13744  (*m_hAllocator->GetVulkanFunctions().vkFlushMappedMemoryRanges)(m_hAllocator->m_hDevice, 1, &memRange);
      +
      13745  }
      +
      13746  }
      +
      13747  }
      +
      13748 
      +
      13749  // Go over all blocks in reverse order. Unmap those that were mapped just for defragmentation.
      +
      13750  // Regardless of pCtx->res == VK_SUCCESS.
      +
      13751  for(size_t blockIndex = blockCount; blockIndex--; )
      +
      13752  {
      +
      13753  const BlockInfo& currBlockInfo = blockInfo[blockIndex];
      +
      13754  if((currBlockInfo.flags & BLOCK_FLAG_MAPPED_FOR_DEFRAGMENTATION) != 0)
      +
      13755  {
      +
      13756  VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex];
      +
      13757  pBlock->Unmap(m_hAllocator, 1);
      +
      13758  }
      +
      13759  }
      +
      13760 }
      +
      13761 
      +
      13762 void VmaBlockVector::ApplyDefragmentationMovesGpu(
      +
      13763  class VmaBlockVectorDefragmentationContext* pDefragCtx,
      +
      13764  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
      +
      13765  VkCommandBuffer commandBuffer)
      +
      13766 {
      +
      13767  const size_t blockCount = m_Blocks.size();
      13768 
      -
      13769  // Accumulate statistics.
      -
      13770  if(pStats != VMA_NULL)
      -
      13771  {
      -
      13772  const VkDeviceSize bytesMoved = pCtx->GetAlgorithm()->GetBytesMoved();
      -
      13773  const uint32_t allocationsMoved = pCtx->GetAlgorithm()->GetAllocationsMoved();
      -
      13774  pStats->bytesMoved += bytesMoved;
      -
      13775  pStats->allocationsMoved += allocationsMoved;
      -
      13776  VMA_ASSERT(bytesMoved <= maxBytesToMove);
      -
      13777  VMA_ASSERT(allocationsMoved <= maxAllocationsToMove);
      -
      13778  if(defragmentOnGpu)
      -
      13779  {
      -
      13780  maxGpuBytesToMove -= bytesMoved;
      -
      13781  maxGpuAllocationsToMove -= allocationsMoved;
      -
      13782  }
      -
      13783  else
      -
      13784  {
      -
      13785  maxCpuBytesToMove -= bytesMoved;
      -
      13786  maxCpuAllocationsToMove -= allocationsMoved;
      -
      13787  }
      -
      13788  }
      -
      13789 
      - -
      13791  {
      -
      13792  if(m_hAllocator->m_UseMutex)
      -
      13793  m_Mutex.UnlockWrite();
      -
      13794 
      -
      13795  if(pCtx->res >= VK_SUCCESS && !pCtx->defragmentationMoves.empty())
      -
      13796  pCtx->res = VK_NOT_READY;
      -
      13797 
      -
      13798  return;
      -
      13799  }
      -
      13800 
      -
      13801  if(pCtx->res >= VK_SUCCESS)
      -
      13802  {
      -
      13803  if(defragmentOnGpu)
      -
      13804  {
      -
      13805  ApplyDefragmentationMovesGpu(pCtx, pCtx->defragmentationMoves, commandBuffer);
      -
      13806  }
      -
      13807  else
      -
      13808  {
      -
      13809  ApplyDefragmentationMovesCpu(pCtx, pCtx->defragmentationMoves);
      -
      13810  }
      -
      13811  }
      -
      13812  }
      -
      13813 }
      -
      13814 
      -
      13815 void VmaBlockVector::DefragmentationEnd(
      -
      13816  class VmaBlockVectorDefragmentationContext* pCtx,
      -
      13817  uint32_t flags,
      -
      13818  VmaDefragmentationStats* pStats)
      -
      13819 {
      -
      13820  if(flags & VMA_DEFRAGMENTATION_FLAG_INCREMENTAL && m_hAllocator->m_UseMutex)
      -
      13821  {
      -
      13822  VMA_ASSERT(pCtx->mutexLocked == false);
      -
      13823 
      -
      13824  // Incremental defragmentation doesn't hold the lock, so when we enter here we don't actually have any
      -
      13825  // lock protecting us. Since we mutate state here, we have to take the lock out now
      -
      13826  m_Mutex.LockWrite();
      -
      13827  pCtx->mutexLocked = true;
      -
      13828  }
      -
      13829 
      -
      13830  // If the mutex isn't locked we didn't do any work and there is nothing to delete.
      -
      13831  if(pCtx->mutexLocked || !m_hAllocator->m_UseMutex)
      -
      13832  {
      -
      13833  // Destroy buffers.
      -
      13834  for(size_t blockIndex = pCtx->blockContexts.size(); blockIndex--;)
      -
      13835  {
      -
      13836  VmaBlockDefragmentationContext &blockCtx = pCtx->blockContexts[blockIndex];
      -
      13837  if(blockCtx.hBuffer)
      -
      13838  {
      -
      13839  (*m_hAllocator->GetVulkanFunctions().vkDestroyBuffer)(m_hAllocator->m_hDevice, blockCtx.hBuffer, m_hAllocator->GetAllocationCallbacks());
      -
      13840  }
      -
      13841  }
      -
      13842 
      -
      13843  if(pCtx->res >= VK_SUCCESS)
      -
      13844  {
      -
      13845  FreeEmptyBlocks(pStats);
      -
      13846  }
      -
      13847  }
      -
      13848 
      -
      13849  if(pCtx->mutexLocked)
      -
      13850  {
      -
      13851  VMA_ASSERT(m_hAllocator->m_UseMutex);
      -
      13852  m_Mutex.UnlockWrite();
      -
      13853  }
      -
      13854 }
      -
      13855 
      -
      13856 uint32_t VmaBlockVector::ProcessDefragmentations(
      -
      13857  class VmaBlockVectorDefragmentationContext *pCtx,
      -
      13858  VmaDefragmentationPassMoveInfo* pMove, uint32_t maxMoves)
      -
      13859 {
      -
      13860  VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
      -
      13861 
      -
      13862  const uint32_t moveCount = VMA_MIN(uint32_t(pCtx->defragmentationMoves.size()) - pCtx->defragmentationMovesProcessed, maxMoves);
      -
      13863 
      -
      13864  for(uint32_t i = 0; i < moveCount; ++ i)
      -
      13865  {
      -
      13866  VmaDefragmentationMove& move = pCtx->defragmentationMoves[pCtx->defragmentationMovesProcessed + i];
      -
      13867 
      -
      13868  pMove->allocation = move.hAllocation;
      -
      13869  pMove->memory = move.pDstBlock->GetDeviceMemory();
      -
      13870  pMove->offset = move.dstOffset;
      -
      13871 
      -
      13872  ++ pMove;
      -
      13873  }
      -
      13874 
      -
      13875  pCtx->defragmentationMovesProcessed += moveCount;
      -
      13876 
      -
      13877  return moveCount;
      -
      13878 }
      -
      13879 
      -
      13880 void VmaBlockVector::CommitDefragmentations(
      -
      13881  class VmaBlockVectorDefragmentationContext *pCtx,
      -
      13882  VmaDefragmentationStats* pStats)
      -
      13883 {
      -
      13884  VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
      -
      13885 
      -
      13886  for(uint32_t i = pCtx->defragmentationMovesCommitted; i < pCtx->defragmentationMovesProcessed; ++ i)
      -
      13887  {
      -
      13888  const VmaDefragmentationMove &move = pCtx->defragmentationMoves[i];
      -
      13889 
      -
      13890  move.pSrcBlock->m_pMetadata->FreeAtOffset(move.srcOffset);
      -
      13891  move.hAllocation->ChangeBlockAllocation(m_hAllocator, move.pDstBlock, move.dstOffset);
      -
      13892  }
      -
      13893 
      -
      13894  pCtx->defragmentationMovesCommitted = pCtx->defragmentationMovesProcessed;
      -
      13895  FreeEmptyBlocks(pStats);
      -
      13896 }
      +
      13769  pDefragCtx->blockContexts.resize(blockCount);
      +
      13770  memset(pDefragCtx->blockContexts.data(), 0, blockCount * sizeof(VmaBlockDefragmentationContext));
      +
      13771 
      +
      13772  // Go over all moves. Mark blocks that are used with BLOCK_FLAG_USED.
      +
      13773  const size_t moveCount = moves.size();
      +
      13774  for(size_t moveIndex = 0; moveIndex < moveCount; ++moveIndex)
      +
      13775  {
      +
      13776  const VmaDefragmentationMove& move = moves[moveIndex];
      +
      13777 
      +
      13778  //if(move.type == VMA_ALLOCATION_TYPE_UNKNOWN)
      +
      13779  {
      +
      13780  // Old school move still require us to map the whole block
      +
      13781  pDefragCtx->blockContexts[move.srcBlockIndex].flags |= VmaBlockDefragmentationContext::BLOCK_FLAG_USED;
      +
      13782  pDefragCtx->blockContexts[move.dstBlockIndex].flags |= VmaBlockDefragmentationContext::BLOCK_FLAG_USED;
      +
      13783  }
      +
      13784  }
      +
      13785 
      +
      13786  VMA_ASSERT(pDefragCtx->res == VK_SUCCESS);
      +
      13787 
      +
      13788  // Go over all blocks. Create and bind buffer for whole block if necessary.
      +
      13789  {
      +
      13790  VkBufferCreateInfo bufCreateInfo;
      +
      13791  VmaFillGpuDefragmentationBufferCreateInfo(bufCreateInfo);
      +
      13792 
      +
      13793  for(size_t blockIndex = 0; pDefragCtx->res == VK_SUCCESS && blockIndex < blockCount; ++blockIndex)
      +
      13794  {
      +
      13795  VmaBlockDefragmentationContext& currBlockCtx = pDefragCtx->blockContexts[blockIndex];
      +
      13796  VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex];
      +
      13797  if((currBlockCtx.flags & VmaBlockDefragmentationContext::BLOCK_FLAG_USED) != 0)
      +
      13798  {
      +
      13799  bufCreateInfo.size = pBlock->m_pMetadata->GetSize();
      +
      13800  pDefragCtx->res = (*m_hAllocator->GetVulkanFunctions().vkCreateBuffer)(
      +
      13801  m_hAllocator->m_hDevice, &bufCreateInfo, m_hAllocator->GetAllocationCallbacks(), &currBlockCtx.hBuffer);
      +
      13802  if(pDefragCtx->res == VK_SUCCESS)
      +
      13803  {
      +
      13804  pDefragCtx->res = (*m_hAllocator->GetVulkanFunctions().vkBindBufferMemory)(
      +
      13805  m_hAllocator->m_hDevice, currBlockCtx.hBuffer, pBlock->GetDeviceMemory(), 0);
      +
      13806  }
      +
      13807  }
      +
      13808  }
      +
      13809  }
      +
      13810 
      +
      13811  // Go over all moves. Post data transfer commands to command buffer.
      +
      13812  if(pDefragCtx->res == VK_SUCCESS)
      +
      13813  {
      +
      13814  for(size_t moveIndex = 0; moveIndex < moveCount; ++moveIndex)
      +
      13815  {
      +
      13816  const VmaDefragmentationMove& move = moves[moveIndex];
      +
      13817 
      +
      13818  const VmaBlockDefragmentationContext& srcBlockCtx = pDefragCtx->blockContexts[move.srcBlockIndex];
      +
      13819  const VmaBlockDefragmentationContext& dstBlockCtx = pDefragCtx->blockContexts[move.dstBlockIndex];
      +
      13820 
      +
      13821  VMA_ASSERT(srcBlockCtx.hBuffer && dstBlockCtx.hBuffer);
      +
      13822 
      +
      13823  VkBufferCopy region = {
      +
      13824  move.srcOffset,
      +
      13825  move.dstOffset,
      +
      13826  move.size };
      +
      13827  (*m_hAllocator->GetVulkanFunctions().vkCmdCopyBuffer)(
      +
      13828  commandBuffer, srcBlockCtx.hBuffer, dstBlockCtx.hBuffer, 1, &region);
      +
      13829  }
      +
      13830  }
      +
      13831 
      +
      13832  // Save buffers to defrag context for later destruction.
      +
      13833  if(pDefragCtx->res == VK_SUCCESS && moveCount > 0)
      +
      13834  {
      +
      13835  pDefragCtx->res = VK_NOT_READY;
      +
      13836  }
      +
      13837 }
      +
      13838 
      +
      13839 void VmaBlockVector::FreeEmptyBlocks(VmaDefragmentationStats* pDefragmentationStats)
      +
      13840 {
      +
      13841  for(size_t blockIndex = m_Blocks.size(); blockIndex--; )
      +
      13842  {
      +
      13843  VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex];
      +
      13844  if(pBlock->m_pMetadata->IsEmpty())
      +
      13845  {
      +
      13846  if(m_Blocks.size() > m_MinBlockCount)
      +
      13847  {
      +
      13848  if(pDefragmentationStats != VMA_NULL)
      +
      13849  {
      +
      13850  ++pDefragmentationStats->deviceMemoryBlocksFreed;
      +
      13851  pDefragmentationStats->bytesFreed += pBlock->m_pMetadata->GetSize();
      +
      13852  }
      +
      13853 
      +
      13854  VmaVectorRemove(m_Blocks, blockIndex);
      +
      13855  pBlock->Destroy(m_hAllocator);
      +
      13856  vma_delete(m_hAllocator, pBlock);
      +
      13857  }
      +
      13858  else
      +
      13859  {
      +
      13860  break;
      +
      13861  }
      +
      13862  }
      +
      13863  }
      +
      13864  UpdateHasEmptyBlock();
      +
      13865 }
      +
      13866 
      +
      13867 void VmaBlockVector::UpdateHasEmptyBlock()
      +
      13868 {
      +
      13869  m_HasEmptyBlock = false;
      +
      13870  for(size_t index = 0, count = m_Blocks.size(); index < count; ++index)
      +
      13871  {
      +
      13872  VmaDeviceMemoryBlock* const pBlock = m_Blocks[index];
      +
      13873  if(pBlock->m_pMetadata->IsEmpty())
      +
      13874  {
      +
      13875  m_HasEmptyBlock = true;
      +
      13876  break;
      +
      13877  }
      +
      13878  }
      +
      13879 }
      +
      13880 
      +
      13881 #if VMA_STATS_STRING_ENABLED
      +
      13882 
      +
      13883 void VmaBlockVector::PrintDetailedMap(class VmaJsonWriter& json)
      +
      13884 {
      +
      13885  VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex);
      +
      13886 
      +
      13887  json.BeginObject();
      +
      13888 
      +
      13889  if(IsCustomPool())
      +
      13890  {
      +
      13891  const char* poolName = m_hParentPool->GetName();
      +
      13892  if(poolName != VMA_NULL && poolName[0] != '\0')
      +
      13893  {
      +
      13894  json.WriteString("Name");
      +
      13895  json.WriteString(poolName);
      +
      13896  }
      13897 
      -
      13898 size_t VmaBlockVector::CalcAllocationCount() const
      -
      13899 {
      -
      13900  size_t result = 0;
      -
      13901  for(size_t i = 0; i < m_Blocks.size(); ++i)
      -
      13902  {
      -
      13903  result += m_Blocks[i]->m_pMetadata->GetAllocationCount();
      -
      13904  }
      -
      13905  return result;
      -
      13906 }
      -
      13907 
      -
      13908 bool VmaBlockVector::IsBufferImageGranularityConflictPossible() const
      -
      13909 {
      -
      13910  if(m_BufferImageGranularity == 1)
      -
      13911  {
      -
      13912  return false;
      -
      13913  }
      -
      13914  VmaSuballocationType lastSuballocType = VMA_SUBALLOCATION_TYPE_FREE;
      -
      13915  for(size_t i = 0, count = m_Blocks.size(); i < count; ++i)
      -
      13916  {
      -
      13917  VmaDeviceMemoryBlock* const pBlock = m_Blocks[i];
      -
      13918  VMA_ASSERT(m_Algorithm == 0);
      -
      13919  VmaBlockMetadata_Generic* const pMetadata = (VmaBlockMetadata_Generic*)pBlock->m_pMetadata;
      -
      13920  if(pMetadata->IsBufferImageGranularityConflictPossible(m_BufferImageGranularity, lastSuballocType))
      +
      13898  json.WriteString("MemoryTypeIndex");
      +
      13899  json.WriteNumber(m_MemoryTypeIndex);
      +
      13900 
      +
      13901  json.WriteString("BlockSize");
      +
      13902  json.WriteNumber(m_PreferredBlockSize);
      +
      13903 
      +
      13904  json.WriteString("BlockCount");
      +
      13905  json.BeginObject(true);
      +
      13906  if(m_MinBlockCount > 0)
      +
      13907  {
      +
      13908  json.WriteString("Min");
      +
      13909  json.WriteNumber((uint64_t)m_MinBlockCount);
      +
      13910  }
      +
      13911  if(m_MaxBlockCount < SIZE_MAX)
      +
      13912  {
      +
      13913  json.WriteString("Max");
      +
      13914  json.WriteNumber((uint64_t)m_MaxBlockCount);
      +
      13915  }
      +
      13916  json.WriteString("Cur");
      +
      13917  json.WriteNumber((uint64_t)m_Blocks.size());
      +
      13918  json.EndObject();
      +
      13919 
      +
      13920  if(m_FrameInUseCount > 0)
      13921  {
      -
      13922  return true;
      -
      13923  }
      -
      13924  }
      -
      13925  return false;
      -
      13926 }
      -
      13927 
      -
      13928 void VmaBlockVector::MakePoolAllocationsLost(
      -
      13929  uint32_t currentFrameIndex,
      -
      13930  size_t* pLostAllocationCount)
      -
      13931 {
      -
      13932  VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
      -
      13933  size_t lostAllocationCount = 0;
      -
      13934  for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
      -
      13935  {
      -
      13936  VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex];
      -
      13937  VMA_ASSERT(pBlock);
      -
      13938  lostAllocationCount += pBlock->m_pMetadata->MakeAllocationsLost(currentFrameIndex, m_FrameInUseCount);
      -
      13939  }
      -
      13940  if(pLostAllocationCount != VMA_NULL)
      +
      13922  json.WriteString("FrameInUseCount");
      +
      13923  json.WriteNumber(m_FrameInUseCount);
      +
      13924  }
      +
      13925 
      +
      13926  if(m_Algorithm != 0)
      +
      13927  {
      +
      13928  json.WriteString("Algorithm");
      +
      13929  json.WriteString(VmaAlgorithmToStr(m_Algorithm));
      +
      13930  }
      +
      13931  }
      +
      13932  else
      +
      13933  {
      +
      13934  json.WriteString("PreferredBlockSize");
      +
      13935  json.WriteNumber(m_PreferredBlockSize);
      +
      13936  }
      +
      13937 
      +
      13938  json.WriteString("Blocks");
      +
      13939  json.BeginObject();
      +
      13940  for(size_t i = 0; i < m_Blocks.size(); ++i)
      13941  {
      -
      13942  *pLostAllocationCount = lostAllocationCount;
      -
      13943  }
      -
      13944 }
      +
      13942  json.BeginString();
      +
      13943  json.ContinueString(m_Blocks[i]->GetId());
      +
      13944  json.EndString();
      13945 
      -
      13946 VkResult VmaBlockVector::CheckCorruption()
      -
      13947 {
      -
      13948  if(!IsCorruptionDetectionEnabled())
      -
      13949  {
      -
      13950  return VK_ERROR_FEATURE_NOT_PRESENT;
      -
      13951  }
      +
      13946  m_Blocks[i]->m_pMetadata->PrintDetailedMap(json);
      +
      13947  }
      +
      13948  json.EndObject();
      +
      13949 
      +
      13950  json.EndObject();
      +
      13951 }
      13952 
      -
      13953  VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex);
      -
      13954  for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
      -
      13955  {
      -
      13956  VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex];
      -
      13957  VMA_ASSERT(pBlock);
      -
      13958  VkResult res = pBlock->CheckCorruption(m_hAllocator);
      -
      13959  if(res != VK_SUCCESS)
      -
      13960  {
      -
      13961  return res;
      -
      13962  }
      -
      13963  }
      -
      13964  return VK_SUCCESS;
      -
      13965 }
      -
      13966 
      -
      13967 void VmaBlockVector::AddStats(VmaStats* pStats)
      -
      13968 {
      -
      13969  const uint32_t memTypeIndex = m_MemoryTypeIndex;
      -
      13970  const uint32_t memHeapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(memTypeIndex);
      -
      13971 
      -
      13972  VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex);
      +
      13953 #endif // #if VMA_STATS_STRING_ENABLED
      +
      13954 
      +
      13955 void VmaBlockVector::Defragment(
      +
      13956  class VmaBlockVectorDefragmentationContext* pCtx,
      + +
      13958  VkDeviceSize& maxCpuBytesToMove, uint32_t& maxCpuAllocationsToMove,
      +
      13959  VkDeviceSize& maxGpuBytesToMove, uint32_t& maxGpuAllocationsToMove,
      +
      13960  VkCommandBuffer commandBuffer)
      +
      13961 {
      +
      13962  pCtx->res = VK_SUCCESS;
      +
      13963 
      +
      13964  const VkMemoryPropertyFlags memPropFlags =
      +
      13965  m_hAllocator->m_MemProps.memoryTypes[m_MemoryTypeIndex].propertyFlags;
      +
      13966  const bool isHostVisible = (memPropFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0;
      +
      13967 
      +
      13968  const bool canDefragmentOnCpu = maxCpuBytesToMove > 0 && maxCpuAllocationsToMove > 0 &&
      +
      13969  isHostVisible;
      +
      13970  const bool canDefragmentOnGpu = maxGpuBytesToMove > 0 && maxGpuAllocationsToMove > 0 &&
      +
      13971  !IsCorruptionDetectionEnabled() &&
      +
      13972  ((1u << m_MemoryTypeIndex) & m_hAllocator->GetGpuDefragmentationMemoryTypeBits()) != 0;
      13973 
      -
      13974  for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
      -
      13975  {
      -
      13976  const VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex];
      -
      13977  VMA_ASSERT(pBlock);
      -
      13978  VMA_HEAVY_ASSERT(pBlock->Validate());
      -
      13979  VmaStatInfo allocationStatInfo;
      -
      13980  pBlock->m_pMetadata->CalcAllocationStatInfo(allocationStatInfo);
      -
      13981  VmaAddStatInfo(pStats->total, allocationStatInfo);
      -
      13982  VmaAddStatInfo(pStats->memoryType[memTypeIndex], allocationStatInfo);
      -
      13983  VmaAddStatInfo(pStats->memoryHeap[memHeapIndex], allocationStatInfo);
      -
      13984  }
      -
      13985 }
      -
      13986 
      -
      13988 // VmaDefragmentationAlgorithm_Generic members definition
      +
      13974  // There are options to defragment this memory type.
      +
      13975  if(canDefragmentOnCpu || canDefragmentOnGpu)
      +
      13976  {
      +
      13977  bool defragmentOnGpu;
      +
      13978  // There is only one option to defragment this memory type.
      +
      13979  if(canDefragmentOnGpu != canDefragmentOnCpu)
      +
      13980  {
      +
      13981  defragmentOnGpu = canDefragmentOnGpu;
      +
      13982  }
      +
      13983  // Both options are available: Heuristics to choose the best one.
      +
      13984  else
      +
      13985  {
      +
      13986  defragmentOnGpu = (memPropFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0 ||
      +
      13987  m_hAllocator->IsIntegratedGpu();
      +
      13988  }
      13989 
      -
      13990 VmaDefragmentationAlgorithm_Generic::VmaDefragmentationAlgorithm_Generic(
      -
      13991  VmaAllocator hAllocator,
      -
      13992  VmaBlockVector* pBlockVector,
      -
      13993  uint32_t currentFrameIndex,
      -
      13994  bool overlappingMoveSupported) :
      -
      13995  VmaDefragmentationAlgorithm(hAllocator, pBlockVector, currentFrameIndex),
      -
      13996  m_AllocationCount(0),
      -
      13997  m_AllAllocations(false),
      -
      13998  m_BytesMoved(0),
      -
      13999  m_AllocationsMoved(0),
      -
      14000  m_Blocks(VmaStlAllocator<BlockInfo*>(hAllocator->GetAllocationCallbacks()))
      -
      14001 {
      -
      14002  // Create block info for each block.
      -
      14003  const size_t blockCount = m_pBlockVector->m_Blocks.size();
      -
      14004  for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
      -
      14005  {
      -
      14006  BlockInfo* pBlockInfo = vma_new(m_hAllocator, BlockInfo)(m_hAllocator->GetAllocationCallbacks());
      -
      14007  pBlockInfo->m_OriginalBlockIndex = blockIndex;
      -
      14008  pBlockInfo->m_pBlock = m_pBlockVector->m_Blocks[blockIndex];
      -
      14009  m_Blocks.push_back(pBlockInfo);
      -
      14010  }
      -
      14011 
      -
      14012  // Sort them by m_pBlock pointer value.
      -
      14013  VMA_SORT(m_Blocks.begin(), m_Blocks.end(), BlockPointerLess());
      -
      14014 }
      -
      14015 
      -
      14016 VmaDefragmentationAlgorithm_Generic::~VmaDefragmentationAlgorithm_Generic()
      -
      14017 {
      -
      14018  for(size_t i = m_Blocks.size(); i--; )
      -
      14019  {
      -
      14020  vma_delete(m_hAllocator, m_Blocks[i]);
      -
      14021  }
      -
      14022 }
      -
      14023 
      -
      14024 void VmaDefragmentationAlgorithm_Generic::AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged)
      -
      14025 {
      -
      14026  // Now as we are inside VmaBlockVector::m_Mutex, we can make final check if this allocation was not lost.
      -
      14027  if(hAlloc->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST)
      -
      14028  {
      -
      14029  VmaDeviceMemoryBlock* pBlock = hAlloc->GetBlock();
      -
      14030  BlockInfoVector::iterator it = VmaBinaryFindFirstNotLess(m_Blocks.begin(), m_Blocks.end(), pBlock, BlockPointerLess());
      -
      14031  if(it != m_Blocks.end() && (*it)->m_pBlock == pBlock)
      -
      14032  {
      -
      14033  AllocationInfo allocInfo = AllocationInfo(hAlloc, pChanged);
      -
      14034  (*it)->m_Allocations.push_back(allocInfo);
      -
      14035  }
      -
      14036  else
      -
      14037  {
      -
      14038  VMA_ASSERT(0);
      -
      14039  }
      -
      14040 
      -
      14041  ++m_AllocationCount;
      -
      14042  }
      -
      14043 }
      -
      14044 
      -
      14045 VkResult VmaDefragmentationAlgorithm_Generic::DefragmentRound(
      -
      14046  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
      -
      14047  VkDeviceSize maxBytesToMove,
      -
      14048  uint32_t maxAllocationsToMove,
      -
      14049  bool freeOldAllocations)
      -
      14050 {
      -
      14051  if(m_Blocks.empty())
      -
      14052  {
      -
      14053  return VK_SUCCESS;
      -
      14054  }
      -
      14055 
      -
      14056  // This is a choice based on research.
      -
      14057  // Option 1:
      -
      14058  uint32_t strategy = VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT;
      -
      14059  // Option 2:
      -
      14060  //uint32_t strategy = VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT;
      -
      14061  // Option 3:
      -
      14062  //uint32_t strategy = VMA_ALLOCATION_CREATE_STRATEGY_MIN_FRAGMENTATION_BIT;
      -
      14063 
      -
      14064  size_t srcBlockMinIndex = 0;
      -
      14065  // When FAST_ALGORITHM, move allocations from only last out of blocks that contain non-movable allocations.
      -
      14066  /*
      -
      14067  if(m_AlgorithmFlags & VMA_DEFRAGMENTATION_FAST_ALGORITHM_BIT)
      -
      14068  {
      -
      14069  const size_t blocksWithNonMovableCount = CalcBlocksWithNonMovableCount();
      -
      14070  if(blocksWithNonMovableCount > 0)
      -
      14071  {
      -
      14072  srcBlockMinIndex = blocksWithNonMovableCount - 1;
      -
      14073  }
      -
      14074  }
      -
      14075  */
      -
      14076 
      -
      14077  size_t srcBlockIndex = m_Blocks.size() - 1;
      -
      14078  size_t srcAllocIndex = SIZE_MAX;
      -
      14079  for(;;)
      +
      13990  bool overlappingMoveSupported = !defragmentOnGpu;
      +
      13991 
      +
      13992  if(m_hAllocator->m_UseMutex)
      +
      13993  {
      + +
      13995  {
      +
      13996  if(!m_Mutex.TryLockWrite())
      +
      13997  {
      +
      13998  pCtx->res = VK_ERROR_INITIALIZATION_FAILED;
      +
      13999  return;
      +
      14000  }
      +
      14001  }
      +
      14002  else
      +
      14003  {
      +
      14004  m_Mutex.LockWrite();
      +
      14005  pCtx->mutexLocked = true;
      +
      14006  }
      +
      14007  }
      +
      14008 
      +
      14009  pCtx->Begin(overlappingMoveSupported, flags);
      +
      14010 
      +
      14011  // Defragment.
      +
      14012 
      +
      14013  const VkDeviceSize maxBytesToMove = defragmentOnGpu ? maxGpuBytesToMove : maxCpuBytesToMove;
      +
      14014  const uint32_t maxAllocationsToMove = defragmentOnGpu ? maxGpuAllocationsToMove : maxCpuAllocationsToMove;
      +
      14015  pCtx->res = pCtx->GetAlgorithm()->Defragment(pCtx->defragmentationMoves, maxBytesToMove, maxAllocationsToMove, flags);
      +
      14016 
      +
      14017  // Accumulate statistics.
      +
      14018  if(pStats != VMA_NULL)
      +
      14019  {
      +
      14020  const VkDeviceSize bytesMoved = pCtx->GetAlgorithm()->GetBytesMoved();
      +
      14021  const uint32_t allocationsMoved = pCtx->GetAlgorithm()->GetAllocationsMoved();
      +
      14022  pStats->bytesMoved += bytesMoved;
      +
      14023  pStats->allocationsMoved += allocationsMoved;
      +
      14024  VMA_ASSERT(bytesMoved <= maxBytesToMove);
      +
      14025  VMA_ASSERT(allocationsMoved <= maxAllocationsToMove);
      +
      14026  if(defragmentOnGpu)
      +
      14027  {
      +
      14028  maxGpuBytesToMove -= bytesMoved;
      +
      14029  maxGpuAllocationsToMove -= allocationsMoved;
      +
      14030  }
      +
      14031  else
      +
      14032  {
      +
      14033  maxCpuBytesToMove -= bytesMoved;
      +
      14034  maxCpuAllocationsToMove -= allocationsMoved;
      +
      14035  }
      +
      14036  }
      +
      14037 
      + +
      14039  {
      +
      14040  if(m_hAllocator->m_UseMutex)
      +
      14041  m_Mutex.UnlockWrite();
      +
      14042 
      +
      14043  if(pCtx->res >= VK_SUCCESS && !pCtx->defragmentationMoves.empty())
      +
      14044  pCtx->res = VK_NOT_READY;
      +
      14045 
      +
      14046  return;
      +
      14047  }
      +
      14048 
      +
      14049  if(pCtx->res >= VK_SUCCESS)
      +
      14050  {
      +
      14051  if(defragmentOnGpu)
      +
      14052  {
      +
      14053  ApplyDefragmentationMovesGpu(pCtx, pCtx->defragmentationMoves, commandBuffer);
      +
      14054  }
      +
      14055  else
      +
      14056  {
      +
      14057  ApplyDefragmentationMovesCpu(pCtx, pCtx->defragmentationMoves);
      +
      14058  }
      +
      14059  }
      +
      14060  }
      +
      14061 }
      +
      14062 
      +
      14063 void VmaBlockVector::DefragmentationEnd(
      +
      14064  class VmaBlockVectorDefragmentationContext* pCtx,
      +
      14065  uint32_t flags,
      +
      14066  VmaDefragmentationStats* pStats)
      +
      14067 {
      +
      14068  if(flags & VMA_DEFRAGMENTATION_FLAG_INCREMENTAL && m_hAllocator->m_UseMutex)
      +
      14069  {
      +
      14070  VMA_ASSERT(pCtx->mutexLocked == false);
      +
      14071 
      +
      14072  // Incremental defragmentation doesn't hold the lock, so when we enter here we don't actually have any
      +
      14073  // lock protecting us. Since we mutate state here, we have to take the lock out now
      +
      14074  m_Mutex.LockWrite();
      +
      14075  pCtx->mutexLocked = true;
      +
      14076  }
      +
      14077 
      +
      14078  // If the mutex isn't locked we didn't do any work and there is nothing to delete.
      +
      14079  if(pCtx->mutexLocked || !m_hAllocator->m_UseMutex)
      14080  {
      -
      14081  // 1. Find next allocation to move.
      -
      14082  // 1.1. Start from last to first m_Blocks - they are sorted from most "destination" to most "source".
      -
      14083  // 1.2. Then start from last to first m_Allocations.
      -
      14084  while(srcAllocIndex >= m_Blocks[srcBlockIndex]->m_Allocations.size())
      -
      14085  {
      -
      14086  if(m_Blocks[srcBlockIndex]->m_Allocations.empty())
      -
      14087  {
      -
      14088  // Finished: no more allocations to process.
      -
      14089  if(srcBlockIndex == srcBlockMinIndex)
      -
      14090  {
      -
      14091  return VK_SUCCESS;
      -
      14092  }
      -
      14093  else
      -
      14094  {
      -
      14095  --srcBlockIndex;
      -
      14096  srcAllocIndex = SIZE_MAX;
      -
      14097  }
      -
      14098  }
      -
      14099  else
      -
      14100  {
      -
      14101  srcAllocIndex = m_Blocks[srcBlockIndex]->m_Allocations.size() - 1;
      -
      14102  }
      -
      14103  }
      -
      14104 
      -
      14105  BlockInfo* pSrcBlockInfo = m_Blocks[srcBlockIndex];
      -
      14106  AllocationInfo& allocInfo = pSrcBlockInfo->m_Allocations[srcAllocIndex];
      -
      14107 
      -
      14108  const VkDeviceSize size = allocInfo.m_hAllocation->GetSize();
      -
      14109  const VkDeviceSize srcOffset = allocInfo.m_hAllocation->GetOffset();
      -
      14110  const VkDeviceSize alignment = allocInfo.m_hAllocation->GetAlignment();
      -
      14111  const VmaSuballocationType suballocType = allocInfo.m_hAllocation->GetSuballocationType();
      -
      14112 
      -
      14113  // 2. Try to find new place for this allocation in preceding or current block.
      -
      14114  for(size_t dstBlockIndex = 0; dstBlockIndex <= srcBlockIndex; ++dstBlockIndex)
      -
      14115  {
      -
      14116  BlockInfo* pDstBlockInfo = m_Blocks[dstBlockIndex];
      -
      14117  VmaAllocationRequest dstAllocRequest;
      -
      14118  if(pDstBlockInfo->m_pBlock->m_pMetadata->CreateAllocationRequest(
      -
      14119  m_CurrentFrameIndex,
      -
      14120  m_pBlockVector->GetFrameInUseCount(),
      -
      14121  m_pBlockVector->GetBufferImageGranularity(),
      -
      14122  size,
      -
      14123  alignment,
      -
      14124  false, // upperAddress
      -
      14125  suballocType,
      -
      14126  false, // canMakeOtherLost
      -
      14127  strategy,
      -
      14128  &dstAllocRequest) &&
      -
      14129  MoveMakesSense(
      -
      14130  dstBlockIndex, dstAllocRequest.offset, srcBlockIndex, srcOffset))
      -
      14131  {
      -
      14132  VMA_ASSERT(dstAllocRequest.itemsToMakeLostCount == 0);
      +
      14081  // Destroy buffers.
      +
      14082  for(size_t blockIndex = pCtx->blockContexts.size(); blockIndex--;)
      +
      14083  {
      +
      14084  VmaBlockDefragmentationContext &blockCtx = pCtx->blockContexts[blockIndex];
      +
      14085  if(blockCtx.hBuffer)
      +
      14086  {
      +
      14087  (*m_hAllocator->GetVulkanFunctions().vkDestroyBuffer)(m_hAllocator->m_hDevice, blockCtx.hBuffer, m_hAllocator->GetAllocationCallbacks());
      +
      14088  }
      +
      14089  }
      +
      14090 
      +
      14091  if(pCtx->res >= VK_SUCCESS)
      +
      14092  {
      +
      14093  FreeEmptyBlocks(pStats);
      +
      14094  }
      +
      14095  }
      +
      14096 
      +
      14097  if(pCtx->mutexLocked)
      +
      14098  {
      +
      14099  VMA_ASSERT(m_hAllocator->m_UseMutex);
      +
      14100  m_Mutex.UnlockWrite();
      +
      14101  }
      +
      14102 }
      +
      14103 
      +
      14104 uint32_t VmaBlockVector::ProcessDefragmentations(
      +
      14105  class VmaBlockVectorDefragmentationContext *pCtx,
      +
      14106  VmaDefragmentationPassMoveInfo* pMove, uint32_t maxMoves)
      +
      14107 {
      +
      14108  VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
      +
      14109 
      +
      14110  const uint32_t moveCount = VMA_MIN(uint32_t(pCtx->defragmentationMoves.size()) - pCtx->defragmentationMovesProcessed, maxMoves);
      +
      14111 
      +
      14112  for(uint32_t i = 0; i < moveCount; ++ i)
      +
      14113  {
      +
      14114  VmaDefragmentationMove& move = pCtx->defragmentationMoves[pCtx->defragmentationMovesProcessed + i];
      +
      14115 
      +
      14116  pMove->allocation = move.hAllocation;
      +
      14117  pMove->memory = move.pDstBlock->GetDeviceMemory();
      +
      14118  pMove->offset = move.dstOffset;
      +
      14119 
      +
      14120  ++ pMove;
      +
      14121  }
      +
      14122 
      +
      14123  pCtx->defragmentationMovesProcessed += moveCount;
      +
      14124 
      +
      14125  return moveCount;
      +
      14126 }
      +
      14127 
      +
      14128 void VmaBlockVector::CommitDefragmentations(
      +
      14129  class VmaBlockVectorDefragmentationContext *pCtx,
      +
      14130  VmaDefragmentationStats* pStats)
      +
      14131 {
      +
      14132  VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
      14133 
      -
      14134  // Reached limit on number of allocations or bytes to move.
      -
      14135  if((m_AllocationsMoved + 1 > maxAllocationsToMove) ||
      -
      14136  (m_BytesMoved + size > maxBytesToMove))
      -
      14137  {
      -
      14138  return VK_SUCCESS;
      -
      14139  }
      -
      14140 
      -
      14141  VmaDefragmentationMove move = {};
      -
      14142  move.srcBlockIndex = pSrcBlockInfo->m_OriginalBlockIndex;
      -
      14143  move.dstBlockIndex = pDstBlockInfo->m_OriginalBlockIndex;
      -
      14144  move.srcOffset = srcOffset;
      -
      14145  move.dstOffset = dstAllocRequest.offset;
      -
      14146  move.size = size;
      -
      14147  move.hAllocation = allocInfo.m_hAllocation;
      -
      14148  move.pSrcBlock = pSrcBlockInfo->m_pBlock;
      -
      14149  move.pDstBlock = pDstBlockInfo->m_pBlock;
      -
      14150 
      -
      14151  moves.push_back(move);
      -
      14152 
      -
      14153  pDstBlockInfo->m_pBlock->m_pMetadata->Alloc(
      -
      14154  dstAllocRequest,
      -
      14155  suballocType,
      -
      14156  size,
      -
      14157  allocInfo.m_hAllocation);
      -
      14158 
      -
      14159  if(freeOldAllocations)
      -
      14160  {
      -
      14161  pSrcBlockInfo->m_pBlock->m_pMetadata->FreeAtOffset(srcOffset);
      -
      14162  allocInfo.m_hAllocation->ChangeBlockAllocation(m_hAllocator, pDstBlockInfo->m_pBlock, dstAllocRequest.offset);
      -
      14163  }
      -
      14164 
      -
      14165  if(allocInfo.m_pChanged != VMA_NULL)
      -
      14166  {
      -
      14167  *allocInfo.m_pChanged = VK_TRUE;
      -
      14168  }
      -
      14169 
      -
      14170  ++m_AllocationsMoved;
      -
      14171  m_BytesMoved += size;
      -
      14172 
      -
      14173  VmaVectorRemove(pSrcBlockInfo->m_Allocations, srcAllocIndex);
      -
      14174 
      -
      14175  break;
      -
      14176  }
      -
      14177  }
      -
      14178 
      -
      14179  // If not processed, this allocInfo remains in pBlockInfo->m_Allocations for next round.
      -
      14180 
      -
      14181  if(srcAllocIndex > 0)
      -
      14182  {
      -
      14183  --srcAllocIndex;
      -
      14184  }
      -
      14185  else
      -
      14186  {
      -
      14187  if(srcBlockIndex > 0)
      -
      14188  {
      -
      14189  --srcBlockIndex;
      -
      14190  srcAllocIndex = SIZE_MAX;
      -
      14191  }
      -
      14192  else
      -
      14193  {
      -
      14194  return VK_SUCCESS;
      -
      14195  }
      -
      14196  }
      -
      14197  }
      -
      14198 }
      -
      14199 
      -
      14200 size_t VmaDefragmentationAlgorithm_Generic::CalcBlocksWithNonMovableCount() const
      -
      14201 {
      -
      14202  size_t result = 0;
      -
      14203  for(size_t i = 0; i < m_Blocks.size(); ++i)
      -
      14204  {
      -
      14205  if(m_Blocks[i]->m_HasNonMovableAllocations)
      -
      14206  {
      -
      14207  ++result;
      -
      14208  }
      -
      14209  }
      -
      14210  return result;
      -
      14211 }
      -
      14212 
      -
      14213 VkResult VmaDefragmentationAlgorithm_Generic::Defragment(
      -
      14214  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
      -
      14215  VkDeviceSize maxBytesToMove,
      -
      14216  uint32_t maxAllocationsToMove,
      - -
      14218 {
      -
      14219  if(!m_AllAllocations && m_AllocationCount == 0)
      -
      14220  {
      -
      14221  return VK_SUCCESS;
      -
      14222  }
      -
      14223 
      -
      14224  const size_t blockCount = m_Blocks.size();
      -
      14225  for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
      -
      14226  {
      -
      14227  BlockInfo* pBlockInfo = m_Blocks[blockIndex];
      -
      14228 
      -
      14229  if(m_AllAllocations)
      -
      14230  {
      -
      14231  VmaBlockMetadata_Generic* pMetadata = (VmaBlockMetadata_Generic*)pBlockInfo->m_pBlock->m_pMetadata;
      -
      14232  for(VmaSuballocationList::const_iterator it = pMetadata->m_Suballocations.begin();
      -
      14233  it != pMetadata->m_Suballocations.end();
      -
      14234  ++it)
      -
      14235  {
      -
      14236  if(it->type != VMA_SUBALLOCATION_TYPE_FREE)
      -
      14237  {
      -
      14238  AllocationInfo allocInfo = AllocationInfo(it->hAllocation, VMA_NULL);
      -
      14239  pBlockInfo->m_Allocations.push_back(allocInfo);
      -
      14240  }
      -
      14241  }
      -
      14242  }
      -
      14243 
      -
      14244  pBlockInfo->CalcHasNonMovableAllocations();
      -
      14245 
      -
      14246  // This is a choice based on research.
      -
      14247  // Option 1:
      -
      14248  pBlockInfo->SortAllocationsByOffsetDescending();
      -
      14249  // Option 2:
      -
      14250  //pBlockInfo->SortAllocationsBySizeDescending();
      -
      14251  }
      -
      14252 
      -
      14253  // Sort m_Blocks this time by the main criterium, from most "destination" to most "source" blocks.
      -
      14254  VMA_SORT(m_Blocks.begin(), m_Blocks.end(), BlockInfoCompareMoveDestination());
      -
      14255 
      -
      14256  // This is a choice based on research.
      -
      14257  const uint32_t roundCount = 2;
      -
      14258 
      -
      14259  // Execute defragmentation rounds (the main part).
      -
      14260  VkResult result = VK_SUCCESS;
      -
      14261  for(uint32_t round = 0; (round < roundCount) && (result == VK_SUCCESS); ++round)
      -
      14262  {
      -
      14263  result = DefragmentRound(moves, maxBytesToMove, maxAllocationsToMove, !(flags & VMA_DEFRAGMENTATION_FLAG_INCREMENTAL));
      -
      14264  }
      -
      14265 
      -
      14266  return result;
      -
      14267 }
      -
      14268 
      -
      14269 bool VmaDefragmentationAlgorithm_Generic::MoveMakesSense(
      -
      14270  size_t dstBlockIndex, VkDeviceSize dstOffset,
      -
      14271  size_t srcBlockIndex, VkDeviceSize srcOffset)
      -
      14272 {
      -
      14273  if(dstBlockIndex < srcBlockIndex)
      -
      14274  {
      -
      14275  return true;
      -
      14276  }
      -
      14277  if(dstBlockIndex > srcBlockIndex)
      -
      14278  {
      -
      14279  return false;
      -
      14280  }
      -
      14281  if(dstOffset < srcOffset)
      -
      14282  {
      -
      14283  return true;
      -
      14284  }
      -
      14285  return false;
      -
      14286 }
      -
      14287 
      -
      14289 // VmaDefragmentationAlgorithm_Fast
      -
      14290 
      -
      14291 VmaDefragmentationAlgorithm_Fast::VmaDefragmentationAlgorithm_Fast(
      -
      14292  VmaAllocator hAllocator,
      -
      14293  VmaBlockVector* pBlockVector,
      -
      14294  uint32_t currentFrameIndex,
      -
      14295  bool overlappingMoveSupported) :
      -
      14296  VmaDefragmentationAlgorithm(hAllocator, pBlockVector, currentFrameIndex),
      -
      14297  m_OverlappingMoveSupported(overlappingMoveSupported),
      -
      14298  m_AllocationCount(0),
      -
      14299  m_AllAllocations(false),
      -
      14300  m_BytesMoved(0),
      -
      14301  m_AllocationsMoved(0),
      -
      14302  m_BlockInfos(VmaStlAllocator<BlockInfo>(hAllocator->GetAllocationCallbacks()))
      -
      14303 {
      -
      14304  VMA_ASSERT(VMA_DEBUG_MARGIN == 0);
      -
      14305 
      -
      14306 }
      -
      14307 
      -
      14308 VmaDefragmentationAlgorithm_Fast::~VmaDefragmentationAlgorithm_Fast()
      -
      14309 {
      -
      14310 }
      +
      14134  for(uint32_t i = pCtx->defragmentationMovesCommitted; i < pCtx->defragmentationMovesProcessed; ++ i)
      +
      14135  {
      +
      14136  const VmaDefragmentationMove &move = pCtx->defragmentationMoves[i];
      +
      14137 
      +
      14138  move.pSrcBlock->m_pMetadata->FreeAtOffset(move.srcOffset);
      +
      14139  move.hAllocation->ChangeBlockAllocation(m_hAllocator, move.pDstBlock, move.dstOffset);
      +
      14140  }
      +
      14141 
      +
      14142  pCtx->defragmentationMovesCommitted = pCtx->defragmentationMovesProcessed;
      +
      14143  FreeEmptyBlocks(pStats);
      +
      14144 }
      +
      14145 
      +
      14146 size_t VmaBlockVector::CalcAllocationCount() const
      +
      14147 {
      +
      14148  size_t result = 0;
      +
      14149  for(size_t i = 0; i < m_Blocks.size(); ++i)
      +
      14150  {
      +
      14151  result += m_Blocks[i]->m_pMetadata->GetAllocationCount();
      +
      14152  }
      +
      14153  return result;
      +
      14154 }
      +
      14155 
      +
      14156 bool VmaBlockVector::IsBufferImageGranularityConflictPossible() const
      +
      14157 {
      +
      14158  if(m_BufferImageGranularity == 1)
      +
      14159  {
      +
      14160  return false;
      +
      14161  }
      +
      14162  VmaSuballocationType lastSuballocType = VMA_SUBALLOCATION_TYPE_FREE;
      +
      14163  for(size_t i = 0, count = m_Blocks.size(); i < count; ++i)
      +
      14164  {
      +
      14165  VmaDeviceMemoryBlock* const pBlock = m_Blocks[i];
      +
      14166  VMA_ASSERT(m_Algorithm == 0);
      +
      14167  VmaBlockMetadata_Generic* const pMetadata = (VmaBlockMetadata_Generic*)pBlock->m_pMetadata;
      +
      14168  if(pMetadata->IsBufferImageGranularityConflictPossible(m_BufferImageGranularity, lastSuballocType))
      +
      14169  {
      +
      14170  return true;
      +
      14171  }
      +
      14172  }
      +
      14173  return false;
      +
      14174 }
      +
      14175 
      +
      14176 void VmaBlockVector::MakePoolAllocationsLost(
      +
      14177  uint32_t currentFrameIndex,
      +
      14178  size_t* pLostAllocationCount)
      +
      14179 {
      +
      14180  VmaMutexLockWrite lock(m_Mutex, m_hAllocator->m_UseMutex);
      +
      14181  size_t lostAllocationCount = 0;
      +
      14182  for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
      +
      14183  {
      +
      14184  VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex];
      +
      14185  VMA_ASSERT(pBlock);
      +
      14186  lostAllocationCount += pBlock->m_pMetadata->MakeAllocationsLost(currentFrameIndex, m_FrameInUseCount);
      +
      14187  }
      +
      14188  if(pLostAllocationCount != VMA_NULL)
      +
      14189  {
      +
      14190  *pLostAllocationCount = lostAllocationCount;
      +
      14191  }
      +
      14192 }
      +
      14193 
      +
      14194 VkResult VmaBlockVector::CheckCorruption()
      +
      14195 {
      +
      14196  if(!IsCorruptionDetectionEnabled())
      +
      14197  {
      +
      14198  return VK_ERROR_FEATURE_NOT_PRESENT;
      +
      14199  }
      +
      14200 
      +
      14201  VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex);
      +
      14202  for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
      +
      14203  {
      +
      14204  VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex];
      +
      14205  VMA_ASSERT(pBlock);
      +
      14206  VkResult res = pBlock->CheckCorruption(m_hAllocator);
      +
      14207  if(res != VK_SUCCESS)
      +
      14208  {
      +
      14209  return res;
      +
      14210  }
      +
      14211  }
      +
      14212  return VK_SUCCESS;
      +
      14213 }
      +
      14214 
      +
      14215 void VmaBlockVector::AddStats(VmaStats* pStats)
      +
      14216 {
      +
      14217  const uint32_t memTypeIndex = m_MemoryTypeIndex;
      +
      14218  const uint32_t memHeapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(memTypeIndex);
      +
      14219 
      +
      14220  VmaMutexLockRead lock(m_Mutex, m_hAllocator->m_UseMutex);
      +
      14221 
      +
      14222  for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
      +
      14223  {
      +
      14224  const VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex];
      +
      14225  VMA_ASSERT(pBlock);
      +
      14226  VMA_HEAVY_ASSERT(pBlock->Validate());
      +
      14227  VmaStatInfo allocationStatInfo;
      +
      14228  pBlock->m_pMetadata->CalcAllocationStatInfo(allocationStatInfo);
      +
      14229  VmaAddStatInfo(pStats->total, allocationStatInfo);
      +
      14230  VmaAddStatInfo(pStats->memoryType[memTypeIndex], allocationStatInfo);
      +
      14231  VmaAddStatInfo(pStats->memoryHeap[memHeapIndex], allocationStatInfo);
      +
      14232  }
      +
      14233 }
      +
      14234 
      +
      14236 // VmaDefragmentationAlgorithm_Generic members definition
      +
      14237 
      +
      14238 VmaDefragmentationAlgorithm_Generic::VmaDefragmentationAlgorithm_Generic(
      +
      14239  VmaAllocator hAllocator,
      +
      14240  VmaBlockVector* pBlockVector,
      +
      14241  uint32_t currentFrameIndex,
      +
      14242  bool overlappingMoveSupported) :
      +
      14243  VmaDefragmentationAlgorithm(hAllocator, pBlockVector, currentFrameIndex),
      +
      14244  m_AllocationCount(0),
      +
      14245  m_AllAllocations(false),
      +
      14246  m_BytesMoved(0),
      +
      14247  m_AllocationsMoved(0),
      +
      14248  m_Blocks(VmaStlAllocator<BlockInfo*>(hAllocator->GetAllocationCallbacks()))
      +
      14249 {
      +
      14250  // Create block info for each block.
      +
      14251  const size_t blockCount = m_pBlockVector->m_Blocks.size();
      +
      14252  for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
      +
      14253  {
      +
      14254  BlockInfo* pBlockInfo = vma_new(m_hAllocator, BlockInfo)(m_hAllocator->GetAllocationCallbacks());
      +
      14255  pBlockInfo->m_OriginalBlockIndex = blockIndex;
      +
      14256  pBlockInfo->m_pBlock = m_pBlockVector->m_Blocks[blockIndex];
      +
      14257  m_Blocks.push_back(pBlockInfo);
      +
      14258  }
      +
      14259 
      +
      14260  // Sort them by m_pBlock pointer value.
      +
      14261  VMA_SORT(m_Blocks.begin(), m_Blocks.end(), BlockPointerLess());
      +
      14262 }
      +
      14263 
      +
      14264 VmaDefragmentationAlgorithm_Generic::~VmaDefragmentationAlgorithm_Generic()
      +
      14265 {
      +
      14266  for(size_t i = m_Blocks.size(); i--; )
      +
      14267  {
      +
      14268  vma_delete(m_hAllocator, m_Blocks[i]);
      +
      14269  }
      +
      14270 }
      +
      14271 
      +
      14272 void VmaDefragmentationAlgorithm_Generic::AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged)
      +
      14273 {
      +
      14274  // Now as we are inside VmaBlockVector::m_Mutex, we can make final check if this allocation was not lost.
      +
      14275  if(hAlloc->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST)
      +
      14276  {
      +
      14277  VmaDeviceMemoryBlock* pBlock = hAlloc->GetBlock();
      +
      14278  BlockInfoVector::iterator it = VmaBinaryFindFirstNotLess(m_Blocks.begin(), m_Blocks.end(), pBlock, BlockPointerLess());
      +
      14279  if(it != m_Blocks.end() && (*it)->m_pBlock == pBlock)
      +
      14280  {
      +
      14281  AllocationInfo allocInfo = AllocationInfo(hAlloc, pChanged);
      +
      14282  (*it)->m_Allocations.push_back(allocInfo);
      +
      14283  }
      +
      14284  else
      +
      14285  {
      +
      14286  VMA_ASSERT(0);
      +
      14287  }
      +
      14288 
      +
      14289  ++m_AllocationCount;
      +
      14290  }
      +
      14291 }
      +
      14292 
      +
      14293 VkResult VmaDefragmentationAlgorithm_Generic::DefragmentRound(
      +
      14294  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
      +
      14295  VkDeviceSize maxBytesToMove,
      +
      14296  uint32_t maxAllocationsToMove,
      +
      14297  bool freeOldAllocations)
      +
      14298 {
      +
      14299  if(m_Blocks.empty())
      +
      14300  {
      +
      14301  return VK_SUCCESS;
      +
      14302  }
      +
      14303 
      +
      14304  // This is a choice based on research.
      +
      14305  // Option 1:
      +
      14306  uint32_t strategy = VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT;
      +
      14307  // Option 2:
      +
      14308  //uint32_t strategy = VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT;
      +
      14309  // Option 3:
      +
      14310  //uint32_t strategy = VMA_ALLOCATION_CREATE_STRATEGY_MIN_FRAGMENTATION_BIT;
      14311 
      -
      14312 VkResult VmaDefragmentationAlgorithm_Fast::Defragment(
      -
      14313  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
      -
      14314  VkDeviceSize maxBytesToMove,
      -
      14315  uint32_t maxAllocationsToMove,
      - -
      14317 {
      -
      14318  VMA_ASSERT(m_AllAllocations || m_pBlockVector->CalcAllocationCount() == m_AllocationCount);
      -
      14319 
      -
      14320  const size_t blockCount = m_pBlockVector->GetBlockCount();
      -
      14321  if(blockCount == 0 || maxBytesToMove == 0 || maxAllocationsToMove == 0)
      -
      14322  {
      -
      14323  return VK_SUCCESS;
      -
      14324  }
      -
      14325 
      -
      14326  PreprocessMetadata();
      -
      14327 
      -
      14328  // Sort blocks in order from most destination.
      -
      14329 
      -
      14330  m_BlockInfos.resize(blockCount);
      -
      14331  for(size_t i = 0; i < blockCount; ++i)
      -
      14332  {
      -
      14333  m_BlockInfos[i].origBlockIndex = i;
      -
      14334  }
      -
      14335 
      -
      14336  VMA_SORT(m_BlockInfos.begin(), m_BlockInfos.end(), [this](const BlockInfo& lhs, const BlockInfo& rhs) -> bool {
      -
      14337  return m_pBlockVector->GetBlock(lhs.origBlockIndex)->m_pMetadata->GetSumFreeSize() <
      -
      14338  m_pBlockVector->GetBlock(rhs.origBlockIndex)->m_pMetadata->GetSumFreeSize();
      -
      14339  });
      -
      14340 
      -
      14341  // THE MAIN ALGORITHM
      -
      14342 
      -
      14343  FreeSpaceDatabase freeSpaceDb;
      -
      14344 
      -
      14345  size_t dstBlockInfoIndex = 0;
      -
      14346  size_t dstOrigBlockIndex = m_BlockInfos[dstBlockInfoIndex].origBlockIndex;
      -
      14347  VmaDeviceMemoryBlock* pDstBlock = m_pBlockVector->GetBlock(dstOrigBlockIndex);
      -
      14348  VmaBlockMetadata_Generic* pDstMetadata = (VmaBlockMetadata_Generic*)pDstBlock->m_pMetadata;
      -
      14349  VkDeviceSize dstBlockSize = pDstMetadata->GetSize();
      -
      14350  VkDeviceSize dstOffset = 0;
      -
      14351 
      -
      14352  bool end = false;
      -
      14353  for(size_t srcBlockInfoIndex = 0; !end && srcBlockInfoIndex < blockCount; ++srcBlockInfoIndex)
      -
      14354  {
      -
      14355  const size_t srcOrigBlockIndex = m_BlockInfos[srcBlockInfoIndex].origBlockIndex;
      -
      14356  VmaDeviceMemoryBlock* const pSrcBlock = m_pBlockVector->GetBlock(srcOrigBlockIndex);
      -
      14357  VmaBlockMetadata_Generic* const pSrcMetadata = (VmaBlockMetadata_Generic*)pSrcBlock->m_pMetadata;
      -
      14358  for(VmaSuballocationList::iterator srcSuballocIt = pSrcMetadata->m_Suballocations.begin();
      -
      14359  !end && srcSuballocIt != pSrcMetadata->m_Suballocations.end(); )
      -
      14360  {
      -
      14361  VmaAllocation_T* const pAlloc = srcSuballocIt->hAllocation;
      -
      14362  const VkDeviceSize srcAllocAlignment = pAlloc->GetAlignment();
      -
      14363  const VkDeviceSize srcAllocSize = srcSuballocIt->size;
      -
      14364  if(m_AllocationsMoved == maxAllocationsToMove ||
      -
      14365  m_BytesMoved + srcAllocSize > maxBytesToMove)
      -
      14366  {
      -
      14367  end = true;
      -
      14368  break;
      -
      14369  }
      -
      14370  const VkDeviceSize srcAllocOffset = srcSuballocIt->offset;
      -
      14371 
      -
      14372  VmaDefragmentationMove move = {};
      -
      14373  // Try to place it in one of free spaces from the database.
      -
      14374  size_t freeSpaceInfoIndex;
      -
      14375  VkDeviceSize dstAllocOffset;
      -
      14376  if(freeSpaceDb.Fetch(srcAllocAlignment, srcAllocSize,
      -
      14377  freeSpaceInfoIndex, dstAllocOffset))
      -
      14378  {
      -
      14379  size_t freeSpaceOrigBlockIndex = m_BlockInfos[freeSpaceInfoIndex].origBlockIndex;
      -
      14380  VmaDeviceMemoryBlock* pFreeSpaceBlock = m_pBlockVector->GetBlock(freeSpaceOrigBlockIndex);
      -
      14381  VmaBlockMetadata_Generic* pFreeSpaceMetadata = (VmaBlockMetadata_Generic*)pFreeSpaceBlock->m_pMetadata;
      -
      14382 
      -
      14383  // Same block
      -
      14384  if(freeSpaceInfoIndex == srcBlockInfoIndex)
      +
      14312  size_t srcBlockMinIndex = 0;
      +
      14313  // When FAST_ALGORITHM, move allocations from only last out of blocks that contain non-movable allocations.
      +
      14314  /*
      +
      14315  if(m_AlgorithmFlags & VMA_DEFRAGMENTATION_FAST_ALGORITHM_BIT)
      +
      14316  {
      +
      14317  const size_t blocksWithNonMovableCount = CalcBlocksWithNonMovableCount();
      +
      14318  if(blocksWithNonMovableCount > 0)
      +
      14319  {
      +
      14320  srcBlockMinIndex = blocksWithNonMovableCount - 1;
      +
      14321  }
      +
      14322  }
      +
      14323  */
      +
      14324 
      +
      14325  size_t srcBlockIndex = m_Blocks.size() - 1;
      +
      14326  size_t srcAllocIndex = SIZE_MAX;
      +
      14327  for(;;)
      +
      14328  {
      +
      14329  // 1. Find next allocation to move.
      +
      14330  // 1.1. Start from last to first m_Blocks - they are sorted from most "destination" to most "source".
      +
      14331  // 1.2. Then start from last to first m_Allocations.
      +
      14332  while(srcAllocIndex >= m_Blocks[srcBlockIndex]->m_Allocations.size())
      +
      14333  {
      +
      14334  if(m_Blocks[srcBlockIndex]->m_Allocations.empty())
      +
      14335  {
      +
      14336  // Finished: no more allocations to process.
      +
      14337  if(srcBlockIndex == srcBlockMinIndex)
      +
      14338  {
      +
      14339  return VK_SUCCESS;
      +
      14340  }
      +
      14341  else
      +
      14342  {
      +
      14343  --srcBlockIndex;
      +
      14344  srcAllocIndex = SIZE_MAX;
      +
      14345  }
      +
      14346  }
      +
      14347  else
      +
      14348  {
      +
      14349  srcAllocIndex = m_Blocks[srcBlockIndex]->m_Allocations.size() - 1;
      +
      14350  }
      +
      14351  }
      +
      14352 
      +
      14353  BlockInfo* pSrcBlockInfo = m_Blocks[srcBlockIndex];
      +
      14354  AllocationInfo& allocInfo = pSrcBlockInfo->m_Allocations[srcAllocIndex];
      +
      14355 
      +
      14356  const VkDeviceSize size = allocInfo.m_hAllocation->GetSize();
      +
      14357  const VkDeviceSize srcOffset = allocInfo.m_hAllocation->GetOffset();
      +
      14358  const VkDeviceSize alignment = allocInfo.m_hAllocation->GetAlignment();
      +
      14359  const VmaSuballocationType suballocType = allocInfo.m_hAllocation->GetSuballocationType();
      +
      14360 
      +
      14361  // 2. Try to find new place for this allocation in preceding or current block.
      +
      14362  for(size_t dstBlockIndex = 0; dstBlockIndex <= srcBlockIndex; ++dstBlockIndex)
      +
      14363  {
      +
      14364  BlockInfo* pDstBlockInfo = m_Blocks[dstBlockIndex];
      +
      14365  VmaAllocationRequest dstAllocRequest;
      +
      14366  if(pDstBlockInfo->m_pBlock->m_pMetadata->CreateAllocationRequest(
      +
      14367  m_CurrentFrameIndex,
      +
      14368  m_pBlockVector->GetFrameInUseCount(),
      +
      14369  m_pBlockVector->GetBufferImageGranularity(),
      +
      14370  size,
      +
      14371  alignment,
      +
      14372  false, // upperAddress
      +
      14373  suballocType,
      +
      14374  false, // canMakeOtherLost
      +
      14375  strategy,
      +
      14376  &dstAllocRequest) &&
      +
      14377  MoveMakesSense(
      +
      14378  dstBlockIndex, dstAllocRequest.offset, srcBlockIndex, srcOffset))
      +
      14379  {
      +
      14380  VMA_ASSERT(dstAllocRequest.itemsToMakeLostCount == 0);
      +
      14381 
      +
      14382  // Reached limit on number of allocations or bytes to move.
      +
      14383  if((m_AllocationsMoved + 1 > maxAllocationsToMove) ||
      +
      14384  (m_BytesMoved + size > maxBytesToMove))
      14385  {
      -
      14386  VMA_ASSERT(dstAllocOffset <= srcAllocOffset);
      -
      14387 
      -
      14388  // MOVE OPTION 1: Move the allocation inside the same block by decreasing offset.
      -
      14389 
      -
      14390  VmaSuballocation suballoc = *srcSuballocIt;
      -
      14391  suballoc.offset = dstAllocOffset;
      -
      14392  suballoc.hAllocation->ChangeOffset(dstAllocOffset);
      -
      14393  m_BytesMoved += srcAllocSize;
      -
      14394  ++m_AllocationsMoved;
      -
      14395 
      -
      14396  VmaSuballocationList::iterator nextSuballocIt = srcSuballocIt;
      -
      14397  ++nextSuballocIt;
      -
      14398  pSrcMetadata->m_Suballocations.erase(srcSuballocIt);
      -
      14399  srcSuballocIt = nextSuballocIt;
      +
      14386  return VK_SUCCESS;
      +
      14387  }
      +
      14388 
      +
      14389  VmaDefragmentationMove move = {};
      +
      14390  move.srcBlockIndex = pSrcBlockInfo->m_OriginalBlockIndex;
      +
      14391  move.dstBlockIndex = pDstBlockInfo->m_OriginalBlockIndex;
      +
      14392  move.srcOffset = srcOffset;
      +
      14393  move.dstOffset = dstAllocRequest.offset;
      +
      14394  move.size = size;
      +
      14395  move.hAllocation = allocInfo.m_hAllocation;
      +
      14396  move.pSrcBlock = pSrcBlockInfo->m_pBlock;
      +
      14397  move.pDstBlock = pDstBlockInfo->m_pBlock;
      +
      14398 
      +
      14399  moves.push_back(move);
      14400 
      -
      14401  InsertSuballoc(pFreeSpaceMetadata, suballoc);
      -
      14402 
      -
      14403  move.srcBlockIndex = srcOrigBlockIndex;
      -
      14404  move.dstBlockIndex = freeSpaceOrigBlockIndex;
      -
      14405  move.srcOffset = srcAllocOffset;
      -
      14406  move.dstOffset = dstAllocOffset;
      -
      14407  move.size = srcAllocSize;
      -
      14408 
      -
      14409  moves.push_back(move);
      -
      14410  }
      -
      14411  // Different block
      -
      14412  else
      -
      14413  {
      -
      14414  // MOVE OPTION 2: Move the allocation to a different block.
      -
      14415 
      -
      14416  VMA_ASSERT(freeSpaceInfoIndex < srcBlockInfoIndex);
      +
      14401  pDstBlockInfo->m_pBlock->m_pMetadata->Alloc(
      +
      14402  dstAllocRequest,
      +
      14403  suballocType,
      +
      14404  size,
      +
      14405  allocInfo.m_hAllocation);
      +
      14406 
      +
      14407  if(freeOldAllocations)
      +
      14408  {
      +
      14409  pSrcBlockInfo->m_pBlock->m_pMetadata->FreeAtOffset(srcOffset);
      +
      14410  allocInfo.m_hAllocation->ChangeBlockAllocation(m_hAllocator, pDstBlockInfo->m_pBlock, dstAllocRequest.offset);
      +
      14411  }
      +
      14412 
      +
      14413  if(allocInfo.m_pChanged != VMA_NULL)
      +
      14414  {
      +
      14415  *allocInfo.m_pChanged = VK_TRUE;
      +
      14416  }
      14417 
      -
      14418  VmaSuballocation suballoc = *srcSuballocIt;
      -
      14419  suballoc.offset = dstAllocOffset;
      -
      14420  suballoc.hAllocation->ChangeBlockAllocation(m_hAllocator, pFreeSpaceBlock, dstAllocOffset);
      -
      14421  m_BytesMoved += srcAllocSize;
      -
      14422  ++m_AllocationsMoved;
      -
      14423 
      -
      14424  VmaSuballocationList::iterator nextSuballocIt = srcSuballocIt;
      -
      14425  ++nextSuballocIt;
      -
      14426  pSrcMetadata->m_Suballocations.erase(srcSuballocIt);
      -
      14427  srcSuballocIt = nextSuballocIt;
      +
      14418  ++m_AllocationsMoved;
      +
      14419  m_BytesMoved += size;
      +
      14420 
      +
      14421  VmaVectorRemove(pSrcBlockInfo->m_Allocations, srcAllocIndex);
      +
      14422 
      +
      14423  break;
      +
      14424  }
      +
      14425  }
      +
      14426 
      +
      14427  // If not processed, this allocInfo remains in pBlockInfo->m_Allocations for next round.
      14428 
      -
      14429  InsertSuballoc(pFreeSpaceMetadata, suballoc);
      -
      14430 
      -
      14431  move.srcBlockIndex = srcOrigBlockIndex;
      -
      14432  move.dstBlockIndex = freeSpaceOrigBlockIndex;
      -
      14433  move.srcOffset = srcAllocOffset;
      -
      14434  move.dstOffset = dstAllocOffset;
      -
      14435  move.size = srcAllocSize;
      -
      14436 
      -
      14437  moves.push_back(move);
      -
      14438  }
      +
      14429  if(srcAllocIndex > 0)
      +
      14430  {
      +
      14431  --srcAllocIndex;
      +
      14432  }
      +
      14433  else
      +
      14434  {
      +
      14435  if(srcBlockIndex > 0)
      +
      14436  {
      +
      14437  --srcBlockIndex;
      +
      14438  srcAllocIndex = SIZE_MAX;
      14439  }
      14440  else
      14441  {
      -
      14442  dstAllocOffset = VmaAlignUp(dstOffset, srcAllocAlignment);
      -
      14443 
      -
      14444  // If the allocation doesn't fit before the end of dstBlock, forward to next block.
      -
      14445  while(dstBlockInfoIndex < srcBlockInfoIndex &&
      -
      14446  dstAllocOffset + srcAllocSize > dstBlockSize)
      -
      14447  {
      -
      14448  // But before that, register remaining free space at the end of dst block.
      -
      14449  freeSpaceDb.Register(dstBlockInfoIndex, dstOffset, dstBlockSize - dstOffset);
      -
      14450 
      -
      14451  ++dstBlockInfoIndex;
      -
      14452  dstOrigBlockIndex = m_BlockInfos[dstBlockInfoIndex].origBlockIndex;
      -
      14453  pDstBlock = m_pBlockVector->GetBlock(dstOrigBlockIndex);
      -
      14454  pDstMetadata = (VmaBlockMetadata_Generic*)pDstBlock->m_pMetadata;
      -
      14455  dstBlockSize = pDstMetadata->GetSize();
      -
      14456  dstOffset = 0;
      -
      14457  dstAllocOffset = 0;
      -
      14458  }
      -
      14459 
      -
      14460  // Same block
      -
      14461  if(dstBlockInfoIndex == srcBlockInfoIndex)
      -
      14462  {
      -
      14463  VMA_ASSERT(dstAllocOffset <= srcAllocOffset);
      -
      14464 
      -
      14465  const bool overlap = dstAllocOffset + srcAllocSize > srcAllocOffset;
      -
      14466 
      -
      14467  bool skipOver = overlap;
      -
      14468  if(overlap && m_OverlappingMoveSupported && dstAllocOffset < srcAllocOffset)
      -
      14469  {
      -
      14470  // If destination and source place overlap, skip if it would move it
      -
      14471  // by only < 1/64 of its size.
      -
      14472  skipOver = (srcAllocOffset - dstAllocOffset) * 64 < srcAllocSize;
      -
      14473  }
      -
      14474 
      -
      14475  if(skipOver)
      -
      14476  {
      -
      14477  freeSpaceDb.Register(dstBlockInfoIndex, dstOffset, srcAllocOffset - dstOffset);
      -
      14478 
      -
      14479  dstOffset = srcAllocOffset + srcAllocSize;
      -
      14480  ++srcSuballocIt;
      -
      14481  }
      -
      14482  // MOVE OPTION 1: Move the allocation inside the same block by decreasing offset.
      -
      14483  else
      -
      14484  {
      -
      14485  srcSuballocIt->offset = dstAllocOffset;
      -
      14486  srcSuballocIt->hAllocation->ChangeOffset(dstAllocOffset);
      -
      14487  dstOffset = dstAllocOffset + srcAllocSize;
      -
      14488  m_BytesMoved += srcAllocSize;
      -
      14489  ++m_AllocationsMoved;
      -
      14490  ++srcSuballocIt;
      +
      14442  return VK_SUCCESS;
      +
      14443  }
      +
      14444  }
      +
      14445  }
      +
      14446 }
      +
      14447 
      +
      14448 size_t VmaDefragmentationAlgorithm_Generic::CalcBlocksWithNonMovableCount() const
      +
      14449 {
      +
      14450  size_t result = 0;
      +
      14451  for(size_t i = 0; i < m_Blocks.size(); ++i)
      +
      14452  {
      +
      14453  if(m_Blocks[i]->m_HasNonMovableAllocations)
      +
      14454  {
      +
      14455  ++result;
      +
      14456  }
      +
      14457  }
      +
      14458  return result;
      +
      14459 }
      +
      14460 
      +
      14461 VkResult VmaDefragmentationAlgorithm_Generic::Defragment(
      +
      14462  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
      +
      14463  VkDeviceSize maxBytesToMove,
      +
      14464  uint32_t maxAllocationsToMove,
      + +
      14466 {
      +
      14467  if(!m_AllAllocations && m_AllocationCount == 0)
      +
      14468  {
      +
      14469  return VK_SUCCESS;
      +
      14470  }
      +
      14471 
      +
      14472  const size_t blockCount = m_Blocks.size();
      +
      14473  for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
      +
      14474  {
      +
      14475  BlockInfo* pBlockInfo = m_Blocks[blockIndex];
      +
      14476 
      +
      14477  if(m_AllAllocations)
      +
      14478  {
      +
      14479  VmaBlockMetadata_Generic* pMetadata = (VmaBlockMetadata_Generic*)pBlockInfo->m_pBlock->m_pMetadata;
      +
      14480  for(VmaSuballocationList::const_iterator it = pMetadata->m_Suballocations.begin();
      +
      14481  it != pMetadata->m_Suballocations.end();
      +
      14482  ++it)
      +
      14483  {
      +
      14484  if(it->type != VMA_SUBALLOCATION_TYPE_FREE)
      +
      14485  {
      +
      14486  AllocationInfo allocInfo = AllocationInfo(it->hAllocation, VMA_NULL);
      +
      14487  pBlockInfo->m_Allocations.push_back(allocInfo);
      +
      14488  }
      +
      14489  }
      +
      14490  }
      14491 
      -
      14492  move.srcBlockIndex = srcOrigBlockIndex;
      -
      14493  move.dstBlockIndex = dstOrigBlockIndex;
      -
      14494  move.srcOffset = srcAllocOffset;
      -
      14495  move.dstOffset = dstAllocOffset;
      -
      14496  move.size = srcAllocSize;
      -
      14497 
      -
      14498  moves.push_back(move);
      -
      14499  }
      -
      14500  }
      -
      14501  // Different block
      -
      14502  else
      -
      14503  {
      -
      14504  // MOVE OPTION 2: Move the allocation to a different block.
      -
      14505 
      -
      14506  VMA_ASSERT(dstBlockInfoIndex < srcBlockInfoIndex);
      -
      14507  VMA_ASSERT(dstAllocOffset + srcAllocSize <= dstBlockSize);
      -
      14508 
      -
      14509  VmaSuballocation suballoc = *srcSuballocIt;
      -
      14510  suballoc.offset = dstAllocOffset;
      -
      14511  suballoc.hAllocation->ChangeBlockAllocation(m_hAllocator, pDstBlock, dstAllocOffset);
      -
      14512  dstOffset = dstAllocOffset + srcAllocSize;
      -
      14513  m_BytesMoved += srcAllocSize;
      -
      14514  ++m_AllocationsMoved;
      -
      14515 
      -
      14516  VmaSuballocationList::iterator nextSuballocIt = srcSuballocIt;
      -
      14517  ++nextSuballocIt;
      -
      14518  pSrcMetadata->m_Suballocations.erase(srcSuballocIt);
      -
      14519  srcSuballocIt = nextSuballocIt;
      -
      14520 
      -
      14521  pDstMetadata->m_Suballocations.push_back(suballoc);
      -
      14522 
      -
      14523  move.srcBlockIndex = srcOrigBlockIndex;
      -
      14524  move.dstBlockIndex = dstOrigBlockIndex;
      -
      14525  move.srcOffset = srcAllocOffset;
      -
      14526  move.dstOffset = dstAllocOffset;
      -
      14527  move.size = srcAllocSize;
      -
      14528 
      -
      14529  moves.push_back(move);
      -
      14530  }
      -
      14531  }
      -
      14532  }
      -
      14533  }
      -
      14534 
      -
      14535  m_BlockInfos.clear();
      -
      14536 
      -
      14537  PostprocessMetadata();
      +
      14492  pBlockInfo->CalcHasNonMovableAllocations();
      +
      14493 
      +
      14494  // This is a choice based on research.
      +
      14495  // Option 1:
      +
      14496  pBlockInfo->SortAllocationsByOffsetDescending();
      +
      14497  // Option 2:
      +
      14498  //pBlockInfo->SortAllocationsBySizeDescending();
      +
      14499  }
      +
      14500 
      +
      14501  // Sort m_Blocks this time by the main criterium, from most "destination" to most "source" blocks.
      +
      14502  VMA_SORT(m_Blocks.begin(), m_Blocks.end(), BlockInfoCompareMoveDestination());
      +
      14503 
      +
      14504  // This is a choice based on research.
      +
      14505  const uint32_t roundCount = 2;
      +
      14506 
      +
      14507  // Execute defragmentation rounds (the main part).
      +
      14508  VkResult result = VK_SUCCESS;
      +
      14509  for(uint32_t round = 0; (round < roundCount) && (result == VK_SUCCESS); ++round)
      +
      14510  {
      +
      14511  result = DefragmentRound(moves, maxBytesToMove, maxAllocationsToMove, !(flags & VMA_DEFRAGMENTATION_FLAG_INCREMENTAL));
      +
      14512  }
      +
      14513 
      +
      14514  return result;
      +
      14515 }
      +
      14516 
      +
      14517 bool VmaDefragmentationAlgorithm_Generic::MoveMakesSense(
      +
      14518  size_t dstBlockIndex, VkDeviceSize dstOffset,
      +
      14519  size_t srcBlockIndex, VkDeviceSize srcOffset)
      +
      14520 {
      +
      14521  if(dstBlockIndex < srcBlockIndex)
      +
      14522  {
      +
      14523  return true;
      +
      14524  }
      +
      14525  if(dstBlockIndex > srcBlockIndex)
      +
      14526  {
      +
      14527  return false;
      +
      14528  }
      +
      14529  if(dstOffset < srcOffset)
      +
      14530  {
      +
      14531  return true;
      +
      14532  }
      +
      14533  return false;
      +
      14534 }
      +
      14535 
      +
      14537 // VmaDefragmentationAlgorithm_Fast
      14538 
      -
      14539  return VK_SUCCESS;
      -
      14540 }
      -
      14541 
      -
      14542 void VmaDefragmentationAlgorithm_Fast::PreprocessMetadata()
      -
      14543 {
      -
      14544  const size_t blockCount = m_pBlockVector->GetBlockCount();
      -
      14545  for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
      -
      14546  {
      -
      14547  VmaBlockMetadata_Generic* const pMetadata =
      -
      14548  (VmaBlockMetadata_Generic*)m_pBlockVector->GetBlock(blockIndex)->m_pMetadata;
      -
      14549  pMetadata->m_FreeCount = 0;
      -
      14550  pMetadata->m_SumFreeSize = pMetadata->GetSize();
      -
      14551  pMetadata->m_FreeSuballocationsBySize.clear();
      -
      14552  for(VmaSuballocationList::iterator it = pMetadata->m_Suballocations.begin();
      -
      14553  it != pMetadata->m_Suballocations.end(); )
      -
      14554  {
      -
      14555  if(it->type == VMA_SUBALLOCATION_TYPE_FREE)
      -
      14556  {
      -
      14557  VmaSuballocationList::iterator nextIt = it;
      -
      14558  ++nextIt;
      -
      14559  pMetadata->m_Suballocations.erase(it);
      -
      14560  it = nextIt;
      -
      14561  }
      -
      14562  else
      -
      14563  {
      -
      14564  ++it;
      -
      14565  }
      -
      14566  }
      -
      14567  }
      -
      14568 }
      -
      14569 
      -
      14570 void VmaDefragmentationAlgorithm_Fast::PostprocessMetadata()
      -
      14571 {
      -
      14572  const size_t blockCount = m_pBlockVector->GetBlockCount();
      -
      14573  for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
      -
      14574  {
      -
      14575  VmaBlockMetadata_Generic* const pMetadata =
      -
      14576  (VmaBlockMetadata_Generic*)m_pBlockVector->GetBlock(blockIndex)->m_pMetadata;
      -
      14577  const VkDeviceSize blockSize = pMetadata->GetSize();
      -
      14578 
      -
      14579  // No allocations in this block - entire area is free.
      -
      14580  if(pMetadata->m_Suballocations.empty())
      -
      14581  {
      -
      14582  pMetadata->m_FreeCount = 1;
      -
      14583  //pMetadata->m_SumFreeSize is already set to blockSize.
      -
      14584  VmaSuballocation suballoc = {
      -
      14585  0, // offset
      -
      14586  blockSize, // size
      -
      14587  VMA_NULL, // hAllocation
      -
      14588  VMA_SUBALLOCATION_TYPE_FREE };
      -
      14589  pMetadata->m_Suballocations.push_back(suballoc);
      -
      14590  pMetadata->RegisterFreeSuballocation(pMetadata->m_Suballocations.begin());
      -
      14591  }
      -
      14592  // There are some allocations in this block.
      -
      14593  else
      -
      14594  {
      -
      14595  VkDeviceSize offset = 0;
      -
      14596  VmaSuballocationList::iterator it;
      -
      14597  for(it = pMetadata->m_Suballocations.begin();
      -
      14598  it != pMetadata->m_Suballocations.end();
      -
      14599  ++it)
      -
      14600  {
      -
      14601  VMA_ASSERT(it->type != VMA_SUBALLOCATION_TYPE_FREE);
      -
      14602  VMA_ASSERT(it->offset >= offset);
      -
      14603 
      -
      14604  // Need to insert preceding free space.
      -
      14605  if(it->offset > offset)
      -
      14606  {
      -
      14607  ++pMetadata->m_FreeCount;
      -
      14608  const VkDeviceSize freeSize = it->offset - offset;
      -
      14609  VmaSuballocation suballoc = {
      -
      14610  offset, // offset
      -
      14611  freeSize, // size
      -
      14612  VMA_NULL, // hAllocation
      -
      14613  VMA_SUBALLOCATION_TYPE_FREE };
      -
      14614  VmaSuballocationList::iterator precedingFreeIt = pMetadata->m_Suballocations.insert(it, suballoc);
      -
      14615  if(freeSize >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
      -
      14616  {
      -
      14617  pMetadata->m_FreeSuballocationsBySize.push_back(precedingFreeIt);
      -
      14618  }
      -
      14619  }
      -
      14620 
      -
      14621  pMetadata->m_SumFreeSize -= it->size;
      -
      14622  offset = it->offset + it->size;
      -
      14623  }
      -
      14624 
      -
      14625  // Need to insert trailing free space.
      -
      14626  if(offset < blockSize)
      -
      14627  {
      -
      14628  ++pMetadata->m_FreeCount;
      -
      14629  const VkDeviceSize freeSize = blockSize - offset;
      -
      14630  VmaSuballocation suballoc = {
      -
      14631  offset, // offset
      -
      14632  freeSize, // size
      -
      14633  VMA_NULL, // hAllocation
      -
      14634  VMA_SUBALLOCATION_TYPE_FREE };
      -
      14635  VMA_ASSERT(it == pMetadata->m_Suballocations.end());
      -
      14636  VmaSuballocationList::iterator trailingFreeIt = pMetadata->m_Suballocations.insert(it, suballoc);
      -
      14637  if(freeSize > VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
      -
      14638  {
      -
      14639  pMetadata->m_FreeSuballocationsBySize.push_back(trailingFreeIt);
      -
      14640  }
      -
      14641  }
      -
      14642 
      -
      14643  VMA_SORT(
      -
      14644  pMetadata->m_FreeSuballocationsBySize.begin(),
      -
      14645  pMetadata->m_FreeSuballocationsBySize.end(),
      -
      14646  VmaSuballocationItemSizeLess());
      -
      14647  }
      +
      14539 VmaDefragmentationAlgorithm_Fast::VmaDefragmentationAlgorithm_Fast(
      +
      14540  VmaAllocator hAllocator,
      +
      14541  VmaBlockVector* pBlockVector,
      +
      14542  uint32_t currentFrameIndex,
      +
      14543  bool overlappingMoveSupported) :
      +
      14544  VmaDefragmentationAlgorithm(hAllocator, pBlockVector, currentFrameIndex),
      +
      14545  m_OverlappingMoveSupported(overlappingMoveSupported),
      +
      14546  m_AllocationCount(0),
      +
      14547  m_AllAllocations(false),
      +
      14548  m_BytesMoved(0),
      +
      14549  m_AllocationsMoved(0),
      +
      14550  m_BlockInfos(VmaStlAllocator<BlockInfo>(hAllocator->GetAllocationCallbacks()))
      +
      14551 {
      +
      14552  VMA_ASSERT(VMA_DEBUG_MARGIN == 0);
      +
      14553 
      +
      14554 }
      +
      14555 
      +
      14556 VmaDefragmentationAlgorithm_Fast::~VmaDefragmentationAlgorithm_Fast()
      +
      14557 {
      +
      14558 }
      +
      14559 
      +
      14560 VkResult VmaDefragmentationAlgorithm_Fast::Defragment(
      +
      14561  VmaVector< VmaDefragmentationMove, VmaStlAllocator<VmaDefragmentationMove> >& moves,
      +
      14562  VkDeviceSize maxBytesToMove,
      +
      14563  uint32_t maxAllocationsToMove,
      + +
      14565 {
      +
      14566  VMA_ASSERT(m_AllAllocations || m_pBlockVector->CalcAllocationCount() == m_AllocationCount);
      +
      14567 
      +
      14568  const size_t blockCount = m_pBlockVector->GetBlockCount();
      +
      14569  if(blockCount == 0 || maxBytesToMove == 0 || maxAllocationsToMove == 0)
      +
      14570  {
      +
      14571  return VK_SUCCESS;
      +
      14572  }
      +
      14573 
      +
      14574  PreprocessMetadata();
      +
      14575 
      +
      14576  // Sort blocks in order from most destination.
      +
      14577 
      +
      14578  m_BlockInfos.resize(blockCount);
      +
      14579  for(size_t i = 0; i < blockCount; ++i)
      +
      14580  {
      +
      14581  m_BlockInfos[i].origBlockIndex = i;
      +
      14582  }
      +
      14583 
      +
      14584  VMA_SORT(m_BlockInfos.begin(), m_BlockInfos.end(), [this](const BlockInfo& lhs, const BlockInfo& rhs) -> bool {
      +
      14585  return m_pBlockVector->GetBlock(lhs.origBlockIndex)->m_pMetadata->GetSumFreeSize() <
      +
      14586  m_pBlockVector->GetBlock(rhs.origBlockIndex)->m_pMetadata->GetSumFreeSize();
      +
      14587  });
      +
      14588 
      +
      14589  // THE MAIN ALGORITHM
      +
      14590 
      +
      14591  FreeSpaceDatabase freeSpaceDb;
      +
      14592 
      +
      14593  size_t dstBlockInfoIndex = 0;
      +
      14594  size_t dstOrigBlockIndex = m_BlockInfos[dstBlockInfoIndex].origBlockIndex;
      +
      14595  VmaDeviceMemoryBlock* pDstBlock = m_pBlockVector->GetBlock(dstOrigBlockIndex);
      +
      14596  VmaBlockMetadata_Generic* pDstMetadata = (VmaBlockMetadata_Generic*)pDstBlock->m_pMetadata;
      +
      14597  VkDeviceSize dstBlockSize = pDstMetadata->GetSize();
      +
      14598  VkDeviceSize dstOffset = 0;
      +
      14599 
      +
      14600  bool end = false;
      +
      14601  for(size_t srcBlockInfoIndex = 0; !end && srcBlockInfoIndex < blockCount; ++srcBlockInfoIndex)
      +
      14602  {
      +
      14603  const size_t srcOrigBlockIndex = m_BlockInfos[srcBlockInfoIndex].origBlockIndex;
      +
      14604  VmaDeviceMemoryBlock* const pSrcBlock = m_pBlockVector->GetBlock(srcOrigBlockIndex);
      +
      14605  VmaBlockMetadata_Generic* const pSrcMetadata = (VmaBlockMetadata_Generic*)pSrcBlock->m_pMetadata;
      +
      14606  for(VmaSuballocationList::iterator srcSuballocIt = pSrcMetadata->m_Suballocations.begin();
      +
      14607  !end && srcSuballocIt != pSrcMetadata->m_Suballocations.end(); )
      +
      14608  {
      +
      14609  VmaAllocation_T* const pAlloc = srcSuballocIt->hAllocation;
      +
      14610  const VkDeviceSize srcAllocAlignment = pAlloc->GetAlignment();
      +
      14611  const VkDeviceSize srcAllocSize = srcSuballocIt->size;
      +
      14612  if(m_AllocationsMoved == maxAllocationsToMove ||
      +
      14613  m_BytesMoved + srcAllocSize > maxBytesToMove)
      +
      14614  {
      +
      14615  end = true;
      +
      14616  break;
      +
      14617  }
      +
      14618  const VkDeviceSize srcAllocOffset = srcSuballocIt->offset;
      +
      14619 
      +
      14620  VmaDefragmentationMove move = {};
      +
      14621  // Try to place it in one of free spaces from the database.
      +
      14622  size_t freeSpaceInfoIndex;
      +
      14623  VkDeviceSize dstAllocOffset;
      +
      14624  if(freeSpaceDb.Fetch(srcAllocAlignment, srcAllocSize,
      +
      14625  freeSpaceInfoIndex, dstAllocOffset))
      +
      14626  {
      +
      14627  size_t freeSpaceOrigBlockIndex = m_BlockInfos[freeSpaceInfoIndex].origBlockIndex;
      +
      14628  VmaDeviceMemoryBlock* pFreeSpaceBlock = m_pBlockVector->GetBlock(freeSpaceOrigBlockIndex);
      +
      14629  VmaBlockMetadata_Generic* pFreeSpaceMetadata = (VmaBlockMetadata_Generic*)pFreeSpaceBlock->m_pMetadata;
      +
      14630 
      +
      14631  // Same block
      +
      14632  if(freeSpaceInfoIndex == srcBlockInfoIndex)
      +
      14633  {
      +
      14634  VMA_ASSERT(dstAllocOffset <= srcAllocOffset);
      +
      14635 
      +
      14636  // MOVE OPTION 1: Move the allocation inside the same block by decreasing offset.
      +
      14637 
      +
      14638  VmaSuballocation suballoc = *srcSuballocIt;
      +
      14639  suballoc.offset = dstAllocOffset;
      +
      14640  suballoc.hAllocation->ChangeOffset(dstAllocOffset);
      +
      14641  m_BytesMoved += srcAllocSize;
      +
      14642  ++m_AllocationsMoved;
      +
      14643 
      +
      14644  VmaSuballocationList::iterator nextSuballocIt = srcSuballocIt;
      +
      14645  ++nextSuballocIt;
      +
      14646  pSrcMetadata->m_Suballocations.erase(srcSuballocIt);
      +
      14647  srcSuballocIt = nextSuballocIt;
      14648 
      -
      14649  VMA_HEAVY_ASSERT(pMetadata->Validate());
      -
      14650  }
      -
      14651 }
      -
      14652 
      -
      14653 void VmaDefragmentationAlgorithm_Fast::InsertSuballoc(VmaBlockMetadata_Generic* pMetadata, const VmaSuballocation& suballoc)
      -
      14654 {
      -
      14655  // TODO: Optimize somehow. Remember iterator instead of searching for it linearly.
      -
      14656  VmaSuballocationList::iterator it = pMetadata->m_Suballocations.begin();
      -
      14657  while(it != pMetadata->m_Suballocations.end())
      -
      14658  {
      -
      14659  if(it->offset < suballoc.offset)
      -
      14660  {
      -
      14661  ++it;
      -
      14662  }
      -
      14663  }
      -
      14664  pMetadata->m_Suballocations.insert(it, suballoc);
      -
      14665 }
      -
      14666 
      -
      14668 // VmaBlockVectorDefragmentationContext
      -
      14669 
      -
      14670 VmaBlockVectorDefragmentationContext::VmaBlockVectorDefragmentationContext(
      -
      14671  VmaAllocator hAllocator,
      -
      14672  VmaPool hCustomPool,
      -
      14673  VmaBlockVector* pBlockVector,
      -
      14674  uint32_t currFrameIndex) :
      -
      14675  res(VK_SUCCESS),
      -
      14676  mutexLocked(false),
      -
      14677  blockContexts(VmaStlAllocator<VmaBlockDefragmentationContext>(hAllocator->GetAllocationCallbacks())),
      -
      14678  defragmentationMoves(VmaStlAllocator<VmaDefragmentationMove>(hAllocator->GetAllocationCallbacks())),
      -
      14679  defragmentationMovesProcessed(0),
      -
      14680  defragmentationMovesCommitted(0),
      -
      14681  hasDefragmentationPlan(0),
      -
      14682  m_hAllocator(hAllocator),
      -
      14683  m_hCustomPool(hCustomPool),
      -
      14684  m_pBlockVector(pBlockVector),
      -
      14685  m_CurrFrameIndex(currFrameIndex),
      -
      14686  m_pAlgorithm(VMA_NULL),
      -
      14687  m_Allocations(VmaStlAllocator<AllocInfo>(hAllocator->GetAllocationCallbacks())),
      -
      14688  m_AllAllocations(false)
      -
      14689 {
      -
      14690 }
      +
      14649  InsertSuballoc(pFreeSpaceMetadata, suballoc);
      +
      14650 
      +
      14651  move.srcBlockIndex = srcOrigBlockIndex;
      +
      14652  move.dstBlockIndex = freeSpaceOrigBlockIndex;
      +
      14653  move.srcOffset = srcAllocOffset;
      +
      14654  move.dstOffset = dstAllocOffset;
      +
      14655  move.size = srcAllocSize;
      +
      14656 
      +
      14657  moves.push_back(move);
      +
      14658  }
      +
      14659  // Different block
      +
      14660  else
      +
      14661  {
      +
      14662  // MOVE OPTION 2: Move the allocation to a different block.
      +
      14663 
      +
      14664  VMA_ASSERT(freeSpaceInfoIndex < srcBlockInfoIndex);
      +
      14665 
      +
      14666  VmaSuballocation suballoc = *srcSuballocIt;
      +
      14667  suballoc.offset = dstAllocOffset;
      +
      14668  suballoc.hAllocation->ChangeBlockAllocation(m_hAllocator, pFreeSpaceBlock, dstAllocOffset);
      +
      14669  m_BytesMoved += srcAllocSize;
      +
      14670  ++m_AllocationsMoved;
      +
      14671 
      +
      14672  VmaSuballocationList::iterator nextSuballocIt = srcSuballocIt;
      +
      14673  ++nextSuballocIt;
      +
      14674  pSrcMetadata->m_Suballocations.erase(srcSuballocIt);
      +
      14675  srcSuballocIt = nextSuballocIt;
      +
      14676 
      +
      14677  InsertSuballoc(pFreeSpaceMetadata, suballoc);
      +
      14678 
      +
      14679  move.srcBlockIndex = srcOrigBlockIndex;
      +
      14680  move.dstBlockIndex = freeSpaceOrigBlockIndex;
      +
      14681  move.srcOffset = srcAllocOffset;
      +
      14682  move.dstOffset = dstAllocOffset;
      +
      14683  move.size = srcAllocSize;
      +
      14684 
      +
      14685  moves.push_back(move);
      +
      14686  }
      +
      14687  }
      +
      14688  else
      +
      14689  {
      +
      14690  dstAllocOffset = VmaAlignUp(dstOffset, srcAllocAlignment);
      14691 
      -
      14692 VmaBlockVectorDefragmentationContext::~VmaBlockVectorDefragmentationContext()
      -
      14693 {
      -
      14694  vma_delete(m_hAllocator, m_pAlgorithm);
      -
      14695 }
      -
      14696 
      -
      14697 void VmaBlockVectorDefragmentationContext::AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged)
      -
      14698 {
      -
      14699  AllocInfo info = { hAlloc, pChanged };
      -
      14700  m_Allocations.push_back(info);
      -
      14701 }
      -
      14702 
      -
      14703 void VmaBlockVectorDefragmentationContext::Begin(bool overlappingMoveSupported, VmaDefragmentationFlags flags)
      -
      14704 {
      -
      14705  const bool allAllocations = m_AllAllocations ||
      -
      14706  m_Allocations.size() == m_pBlockVector->CalcAllocationCount();
      +
      14692  // If the allocation doesn't fit before the end of dstBlock, forward to next block.
      +
      14693  while(dstBlockInfoIndex < srcBlockInfoIndex &&
      +
      14694  dstAllocOffset + srcAllocSize > dstBlockSize)
      +
      14695  {
      +
      14696  // But before that, register remaining free space at the end of dst block.
      +
      14697  freeSpaceDb.Register(dstBlockInfoIndex, dstOffset, dstBlockSize - dstOffset);
      +
      14698 
      +
      14699  ++dstBlockInfoIndex;
      +
      14700  dstOrigBlockIndex = m_BlockInfos[dstBlockInfoIndex].origBlockIndex;
      +
      14701  pDstBlock = m_pBlockVector->GetBlock(dstOrigBlockIndex);
      +
      14702  pDstMetadata = (VmaBlockMetadata_Generic*)pDstBlock->m_pMetadata;
      +
      14703  dstBlockSize = pDstMetadata->GetSize();
      +
      14704  dstOffset = 0;
      +
      14705  dstAllocOffset = 0;
      +
      14706  }
      14707 
      -
      14708  /********************************
      -
      14709  HERE IS THE CHOICE OF DEFRAGMENTATION ALGORITHM.
      -
      14710  ********************************/
      -
      14711 
      -
      14712  /*
      -
      14713  Fast algorithm is supported only when certain criteria are met:
      -
      14714  - VMA_DEBUG_MARGIN is 0.
      -
      14715  - All allocations in this block vector are moveable.
      -
      14716  - There is no possibility of image/buffer granularity conflict.
      -
      14717  - The defragmentation is not incremental
      -
      14718  */
      -
      14719  if(VMA_DEBUG_MARGIN == 0 &&
      -
      14720  allAllocations &&
      -
      14721  !m_pBlockVector->IsBufferImageGranularityConflictPossible() &&
      - -
      14723  {
      -
      14724  m_pAlgorithm = vma_new(m_hAllocator, VmaDefragmentationAlgorithm_Fast)(
      -
      14725  m_hAllocator, m_pBlockVector, m_CurrFrameIndex, overlappingMoveSupported);
      -
      14726  }
      -
      14727  else
      -
      14728  {
      -
      14729  m_pAlgorithm = vma_new(m_hAllocator, VmaDefragmentationAlgorithm_Generic)(
      -
      14730  m_hAllocator, m_pBlockVector, m_CurrFrameIndex, overlappingMoveSupported);
      -
      14731  }
      -
      14732 
      -
      14733  if(allAllocations)
      -
      14734  {
      -
      14735  m_pAlgorithm->AddAll();
      -
      14736  }
      -
      14737  else
      -
      14738  {
      -
      14739  for(size_t i = 0, count = m_Allocations.size(); i < count; ++i)
      -
      14740  {
      -
      14741  m_pAlgorithm->AddAllocation(m_Allocations[i].hAlloc, m_Allocations[i].pChanged);
      -
      14742  }
      -
      14743  }
      -
      14744 }
      +
      14708  // Same block
      +
      14709  if(dstBlockInfoIndex == srcBlockInfoIndex)
      +
      14710  {
      +
      14711  VMA_ASSERT(dstAllocOffset <= srcAllocOffset);
      +
      14712 
      +
      14713  const bool overlap = dstAllocOffset + srcAllocSize > srcAllocOffset;
      +
      14714 
      +
      14715  bool skipOver = overlap;
      +
      14716  if(overlap && m_OverlappingMoveSupported && dstAllocOffset < srcAllocOffset)
      +
      14717  {
      +
      14718  // If destination and source place overlap, skip if it would move it
      +
      14719  // by only < 1/64 of its size.
      +
      14720  skipOver = (srcAllocOffset - dstAllocOffset) * 64 < srcAllocSize;
      +
      14721  }
      +
      14722 
      +
      14723  if(skipOver)
      +
      14724  {
      +
      14725  freeSpaceDb.Register(dstBlockInfoIndex, dstOffset, srcAllocOffset - dstOffset);
      +
      14726 
      +
      14727  dstOffset = srcAllocOffset + srcAllocSize;
      +
      14728  ++srcSuballocIt;
      +
      14729  }
      +
      14730  // MOVE OPTION 1: Move the allocation inside the same block by decreasing offset.
      +
      14731  else
      +
      14732  {
      +
      14733  srcSuballocIt->offset = dstAllocOffset;
      +
      14734  srcSuballocIt->hAllocation->ChangeOffset(dstAllocOffset);
      +
      14735  dstOffset = dstAllocOffset + srcAllocSize;
      +
      14736  m_BytesMoved += srcAllocSize;
      +
      14737  ++m_AllocationsMoved;
      +
      14738  ++srcSuballocIt;
      +
      14739 
      +
      14740  move.srcBlockIndex = srcOrigBlockIndex;
      +
      14741  move.dstBlockIndex = dstOrigBlockIndex;
      +
      14742  move.srcOffset = srcAllocOffset;
      +
      14743  move.dstOffset = dstAllocOffset;
      +
      14744  move.size = srcAllocSize;
      14745 
      -
      14747 // VmaDefragmentationContext
      -
      14748 
      -
      14749 VmaDefragmentationContext_T::VmaDefragmentationContext_T(
      -
      14750  VmaAllocator hAllocator,
      -
      14751  uint32_t currFrameIndex,
      -
      14752  uint32_t flags,
      -
      14753  VmaDefragmentationStats* pStats) :
      -
      14754  m_hAllocator(hAllocator),
      -
      14755  m_CurrFrameIndex(currFrameIndex),
      -
      14756  m_Flags(flags),
      -
      14757  m_pStats(pStats),
      -
      14758  m_CustomPoolContexts(VmaStlAllocator<VmaBlockVectorDefragmentationContext*>(hAllocator->GetAllocationCallbacks()))
      -
      14759 {
      -
      14760  memset(m_DefaultPoolContexts, 0, sizeof(m_DefaultPoolContexts));
      -
      14761 }
      -
      14762 
      -
      14763 VmaDefragmentationContext_T::~VmaDefragmentationContext_T()
      -
      14764 {
      -
      14765  for(size_t i = m_CustomPoolContexts.size(); i--; )
      -
      14766  {
      -
      14767  VmaBlockVectorDefragmentationContext* pBlockVectorCtx = m_CustomPoolContexts[i];
      -
      14768  pBlockVectorCtx->GetBlockVector()->DefragmentationEnd(pBlockVectorCtx, m_Flags, m_pStats);
      -
      14769  vma_delete(m_hAllocator, pBlockVectorCtx);
      -
      14770  }
      -
      14771  for(size_t i = m_hAllocator->m_MemProps.memoryTypeCount; i--; )
      -
      14772  {
      -
      14773  VmaBlockVectorDefragmentationContext* pBlockVectorCtx = m_DefaultPoolContexts[i];
      -
      14774  if(pBlockVectorCtx)
      -
      14775  {
      -
      14776  pBlockVectorCtx->GetBlockVector()->DefragmentationEnd(pBlockVectorCtx, m_Flags, m_pStats);
      -
      14777  vma_delete(m_hAllocator, pBlockVectorCtx);
      -
      14778  }
      -
      14779  }
      -
      14780 }
      -
      14781 
      -
      14782 void VmaDefragmentationContext_T::AddPools(uint32_t poolCount, const VmaPool* pPools)
      -
      14783 {
      -
      14784  for(uint32_t poolIndex = 0; poolIndex < poolCount; ++poolIndex)
      -
      14785  {
      -
      14786  VmaPool pool = pPools[poolIndex];
      -
      14787  VMA_ASSERT(pool);
      -
      14788  // Pools with algorithm other than default are not defragmented.
      -
      14789  if(pool->m_BlockVector.GetAlgorithm() == 0)
      -
      14790  {
      -
      14791  VmaBlockVectorDefragmentationContext* pBlockVectorDefragCtx = VMA_NULL;
      -
      14792 
      -
      14793  for(size_t i = m_CustomPoolContexts.size(); i--; )
      -
      14794  {
      -
      14795  if(m_CustomPoolContexts[i]->GetCustomPool() == pool)
      -
      14796  {
      -
      14797  pBlockVectorDefragCtx = m_CustomPoolContexts[i];
      -
      14798  break;
      -
      14799  }
      -
      14800  }
      -
      14801 
      -
      14802  if(!pBlockVectorDefragCtx)
      -
      14803  {
      -
      14804  pBlockVectorDefragCtx = vma_new(m_hAllocator, VmaBlockVectorDefragmentationContext)(
      -
      14805  m_hAllocator,
      -
      14806  pool,
      -
      14807  &pool->m_BlockVector,
      -
      14808  m_CurrFrameIndex);
      -
      14809  m_CustomPoolContexts.push_back(pBlockVectorDefragCtx);
      -
      14810  }
      -
      14811 
      -
      14812  pBlockVectorDefragCtx->AddAll();
      -
      14813  }
      -
      14814  }
      -
      14815 }
      -
      14816 
      -
      14817 void VmaDefragmentationContext_T::AddAllocations(
      -
      14818  uint32_t allocationCount,
      -
      14819  const VmaAllocation* pAllocations,
      -
      14820  VkBool32* pAllocationsChanged)
      -
      14821 {
      -
      14822  // Dispatch pAllocations among defragmentators. Create them when necessary.
      -
      14823  for(uint32_t allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
      -
      14824  {
      -
      14825  const VmaAllocation hAlloc = pAllocations[allocIndex];
      -
      14826  VMA_ASSERT(hAlloc);
      -
      14827  // DedicatedAlloc cannot be defragmented.
      -
      14828  if((hAlloc->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK) &&
      -
      14829  // Lost allocation cannot be defragmented.
      -
      14830  (hAlloc->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST))
      -
      14831  {
      -
      14832  VmaBlockVectorDefragmentationContext* pBlockVectorDefragCtx = VMA_NULL;
      -
      14833 
      -
      14834  const VmaPool hAllocPool = hAlloc->GetBlock()->GetParentPool();
      -
      14835  // This allocation belongs to custom pool.
      -
      14836  if(hAllocPool != VK_NULL_HANDLE)
      -
      14837  {
      -
      14838  // Pools with algorithm other than default are not defragmented.
      -
      14839  if(hAllocPool->m_BlockVector.GetAlgorithm() == 0)
      -
      14840  {
      -
      14841  for(size_t i = m_CustomPoolContexts.size(); i--; )
      -
      14842  {
      -
      14843  if(m_CustomPoolContexts[i]->GetCustomPool() == hAllocPool)
      -
      14844  {
      -
      14845  pBlockVectorDefragCtx = m_CustomPoolContexts[i];
      -
      14846  break;
      -
      14847  }
      -
      14848  }
      -
      14849  if(!pBlockVectorDefragCtx)
      -
      14850  {
      -
      14851  pBlockVectorDefragCtx = vma_new(m_hAllocator, VmaBlockVectorDefragmentationContext)(
      -
      14852  m_hAllocator,
      -
      14853  hAllocPool,
      -
      14854  &hAllocPool->m_BlockVector,
      -
      14855  m_CurrFrameIndex);
      -
      14856  m_CustomPoolContexts.push_back(pBlockVectorDefragCtx);
      -
      14857  }
      -
      14858  }
      -
      14859  }
      -
      14860  // This allocation belongs to default pool.
      -
      14861  else
      -
      14862  {
      -
      14863  const uint32_t memTypeIndex = hAlloc->GetMemoryTypeIndex();
      -
      14864  pBlockVectorDefragCtx = m_DefaultPoolContexts[memTypeIndex];
      -
      14865  if(!pBlockVectorDefragCtx)
      -
      14866  {
      -
      14867  pBlockVectorDefragCtx = vma_new(m_hAllocator, VmaBlockVectorDefragmentationContext)(
      -
      14868  m_hAllocator,
      -
      14869  VMA_NULL, // hCustomPool
      -
      14870  m_hAllocator->m_pBlockVectors[memTypeIndex],
      -
      14871  m_CurrFrameIndex);
      -
      14872  m_DefaultPoolContexts[memTypeIndex] = pBlockVectorDefragCtx;
      -
      14873  }
      -
      14874  }
      -
      14875 
      -
      14876  if(pBlockVectorDefragCtx)
      -
      14877  {
      -
      14878  VkBool32* const pChanged = (pAllocationsChanged != VMA_NULL) ?
      -
      14879  &pAllocationsChanged[allocIndex] : VMA_NULL;
      -
      14880  pBlockVectorDefragCtx->AddAllocation(hAlloc, pChanged);
      -
      14881  }
      -
      14882  }
      -
      14883  }
      -
      14884 }
      -
      14885 
      -
      14886 VkResult VmaDefragmentationContext_T::Defragment(
      -
      14887  VkDeviceSize maxCpuBytesToMove, uint32_t maxCpuAllocationsToMove,
      -
      14888  VkDeviceSize maxGpuBytesToMove, uint32_t maxGpuAllocationsToMove,
      -
      14889  VkCommandBuffer commandBuffer, VmaDefragmentationStats* pStats, VmaDefragmentationFlags flags)
      -
      14890 {
      -
      14891  if(pStats)
      -
      14892  {
      -
      14893  memset(pStats, 0, sizeof(VmaDefragmentationStats));
      -
      14894  }
      -
      14895 
      - -
      14897  {
      -
      14898  // For incremental defragmetnations, we just earmark how much we can move
      -
      14899  // The real meat is in the defragmentation steps
      -
      14900  m_MaxCpuBytesToMove = maxCpuBytesToMove;
      -
      14901  m_MaxCpuAllocationsToMove = maxCpuAllocationsToMove;
      -
      14902 
      -
      14903  m_MaxGpuBytesToMove = maxGpuBytesToMove;
      -
      14904  m_MaxGpuAllocationsToMove = maxGpuAllocationsToMove;
      -
      14905 
      -
      14906  if(m_MaxCpuBytesToMove == 0 && m_MaxCpuAllocationsToMove == 0 &&
      -
      14907  m_MaxGpuBytesToMove == 0 && m_MaxGpuAllocationsToMove == 0)
      -
      14908  return VK_SUCCESS;
      -
      14909 
      -
      14910  return VK_NOT_READY;
      +
      14746  moves.push_back(move);
      +
      14747  }
      +
      14748  }
      +
      14749  // Different block
      +
      14750  else
      +
      14751  {
      +
      14752  // MOVE OPTION 2: Move the allocation to a different block.
      +
      14753 
      +
      14754  VMA_ASSERT(dstBlockInfoIndex < srcBlockInfoIndex);
      +
      14755  VMA_ASSERT(dstAllocOffset + srcAllocSize <= dstBlockSize);
      +
      14756 
      +
      14757  VmaSuballocation suballoc = *srcSuballocIt;
      +
      14758  suballoc.offset = dstAllocOffset;
      +
      14759  suballoc.hAllocation->ChangeBlockAllocation(m_hAllocator, pDstBlock, dstAllocOffset);
      +
      14760  dstOffset = dstAllocOffset + srcAllocSize;
      +
      14761  m_BytesMoved += srcAllocSize;
      +
      14762  ++m_AllocationsMoved;
      +
      14763 
      +
      14764  VmaSuballocationList::iterator nextSuballocIt = srcSuballocIt;
      +
      14765  ++nextSuballocIt;
      +
      14766  pSrcMetadata->m_Suballocations.erase(srcSuballocIt);
      +
      14767  srcSuballocIt = nextSuballocIt;
      +
      14768 
      +
      14769  pDstMetadata->m_Suballocations.push_back(suballoc);
      +
      14770 
      +
      14771  move.srcBlockIndex = srcOrigBlockIndex;
      +
      14772  move.dstBlockIndex = dstOrigBlockIndex;
      +
      14773  move.srcOffset = srcAllocOffset;
      +
      14774  move.dstOffset = dstAllocOffset;
      +
      14775  move.size = srcAllocSize;
      +
      14776 
      +
      14777  moves.push_back(move);
      +
      14778  }
      +
      14779  }
      +
      14780  }
      +
      14781  }
      +
      14782 
      +
      14783  m_BlockInfos.clear();
      +
      14784 
      +
      14785  PostprocessMetadata();
      +
      14786 
      +
      14787  return VK_SUCCESS;
      +
      14788 }
      +
      14789 
      +
      14790 void VmaDefragmentationAlgorithm_Fast::PreprocessMetadata()
      +
      14791 {
      +
      14792  const size_t blockCount = m_pBlockVector->GetBlockCount();
      +
      14793  for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
      +
      14794  {
      +
      14795  VmaBlockMetadata_Generic* const pMetadata =
      +
      14796  (VmaBlockMetadata_Generic*)m_pBlockVector->GetBlock(blockIndex)->m_pMetadata;
      +
      14797  pMetadata->m_FreeCount = 0;
      +
      14798  pMetadata->m_SumFreeSize = pMetadata->GetSize();
      +
      14799  pMetadata->m_FreeSuballocationsBySize.clear();
      +
      14800  for(VmaSuballocationList::iterator it = pMetadata->m_Suballocations.begin();
      +
      14801  it != pMetadata->m_Suballocations.end(); )
      +
      14802  {
      +
      14803  if(it->type == VMA_SUBALLOCATION_TYPE_FREE)
      +
      14804  {
      +
      14805  VmaSuballocationList::iterator nextIt = it;
      +
      14806  ++nextIt;
      +
      14807  pMetadata->m_Suballocations.erase(it);
      +
      14808  it = nextIt;
      +
      14809  }
      +
      14810  else
      +
      14811  {
      +
      14812  ++it;
      +
      14813  }
      +
      14814  }
      +
      14815  }
      +
      14816 }
      +
      14817 
      +
      14818 void VmaDefragmentationAlgorithm_Fast::PostprocessMetadata()
      +
      14819 {
      +
      14820  const size_t blockCount = m_pBlockVector->GetBlockCount();
      +
      14821  for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
      +
      14822  {
      +
      14823  VmaBlockMetadata_Generic* const pMetadata =
      +
      14824  (VmaBlockMetadata_Generic*)m_pBlockVector->GetBlock(blockIndex)->m_pMetadata;
      +
      14825  const VkDeviceSize blockSize = pMetadata->GetSize();
      +
      14826 
      +
      14827  // No allocations in this block - entire area is free.
      +
      14828  if(pMetadata->m_Suballocations.empty())
      +
      14829  {
      +
      14830  pMetadata->m_FreeCount = 1;
      +
      14831  //pMetadata->m_SumFreeSize is already set to blockSize.
      +
      14832  VmaSuballocation suballoc = {
      +
      14833  0, // offset
      +
      14834  blockSize, // size
      +
      14835  VMA_NULL, // hAllocation
      +
      14836  VMA_SUBALLOCATION_TYPE_FREE };
      +
      14837  pMetadata->m_Suballocations.push_back(suballoc);
      +
      14838  pMetadata->RegisterFreeSuballocation(pMetadata->m_Suballocations.begin());
      +
      14839  }
      +
      14840  // There are some allocations in this block.
      +
      14841  else
      +
      14842  {
      +
      14843  VkDeviceSize offset = 0;
      +
      14844  VmaSuballocationList::iterator it;
      +
      14845  for(it = pMetadata->m_Suballocations.begin();
      +
      14846  it != pMetadata->m_Suballocations.end();
      +
      14847  ++it)
      +
      14848  {
      +
      14849  VMA_ASSERT(it->type != VMA_SUBALLOCATION_TYPE_FREE);
      +
      14850  VMA_ASSERT(it->offset >= offset);
      +
      14851 
      +
      14852  // Need to insert preceding free space.
      +
      14853  if(it->offset > offset)
      +
      14854  {
      +
      14855  ++pMetadata->m_FreeCount;
      +
      14856  const VkDeviceSize freeSize = it->offset - offset;
      +
      14857  VmaSuballocation suballoc = {
      +
      14858  offset, // offset
      +
      14859  freeSize, // size
      +
      14860  VMA_NULL, // hAllocation
      +
      14861  VMA_SUBALLOCATION_TYPE_FREE };
      +
      14862  VmaSuballocationList::iterator precedingFreeIt = pMetadata->m_Suballocations.insert(it, suballoc);
      +
      14863  if(freeSize >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
      +
      14864  {
      +
      14865  pMetadata->m_FreeSuballocationsBySize.push_back(precedingFreeIt);
      +
      14866  }
      +
      14867  }
      +
      14868 
      +
      14869  pMetadata->m_SumFreeSize -= it->size;
      +
      14870  offset = it->offset + it->size;
      +
      14871  }
      +
      14872 
      +
      14873  // Need to insert trailing free space.
      +
      14874  if(offset < blockSize)
      +
      14875  {
      +
      14876  ++pMetadata->m_FreeCount;
      +
      14877  const VkDeviceSize freeSize = blockSize - offset;
      +
      14878  VmaSuballocation suballoc = {
      +
      14879  offset, // offset
      +
      14880  freeSize, // size
      +
      14881  VMA_NULL, // hAllocation
      +
      14882  VMA_SUBALLOCATION_TYPE_FREE };
      +
      14883  VMA_ASSERT(it == pMetadata->m_Suballocations.end());
      +
      14884  VmaSuballocationList::iterator trailingFreeIt = pMetadata->m_Suballocations.insert(it, suballoc);
      +
      14885  if(freeSize > VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
      +
      14886  {
      +
      14887  pMetadata->m_FreeSuballocationsBySize.push_back(trailingFreeIt);
      +
      14888  }
      +
      14889  }
      +
      14890 
      +
      14891  VMA_SORT(
      +
      14892  pMetadata->m_FreeSuballocationsBySize.begin(),
      +
      14893  pMetadata->m_FreeSuballocationsBySize.end(),
      +
      14894  VmaSuballocationItemSizeLess());
      +
      14895  }
      +
      14896 
      +
      14897  VMA_HEAVY_ASSERT(pMetadata->Validate());
      +
      14898  }
      +
      14899 }
      +
      14900 
      +
      14901 void VmaDefragmentationAlgorithm_Fast::InsertSuballoc(VmaBlockMetadata_Generic* pMetadata, const VmaSuballocation& suballoc)
      +
      14902 {
      +
      14903  // TODO: Optimize somehow. Remember iterator instead of searching for it linearly.
      +
      14904  VmaSuballocationList::iterator it = pMetadata->m_Suballocations.begin();
      +
      14905  while(it != pMetadata->m_Suballocations.end())
      +
      14906  {
      +
      14907  if(it->offset < suballoc.offset)
      +
      14908  {
      +
      14909  ++it;
      +
      14910  }
      14911  }
      -
      14912 
      -
      14913  if(commandBuffer == VK_NULL_HANDLE)
      -
      14914  {
      -
      14915  maxGpuBytesToMove = 0;
      -
      14916  maxGpuAllocationsToMove = 0;
      -
      14917  }
      -
      14918 
      -
      14919  VkResult res = VK_SUCCESS;
      -
      14920 
      -
      14921  // Process default pools.
      -
      14922  for(uint32_t memTypeIndex = 0;
      -
      14923  memTypeIndex < m_hAllocator->GetMemoryTypeCount() && res >= VK_SUCCESS;
      -
      14924  ++memTypeIndex)
      -
      14925  {
      -
      14926  VmaBlockVectorDefragmentationContext* pBlockVectorCtx = m_DefaultPoolContexts[memTypeIndex];
      -
      14927  if(pBlockVectorCtx)
      -
      14928  {
      -
      14929  VMA_ASSERT(pBlockVectorCtx->GetBlockVector());
      -
      14930  pBlockVectorCtx->GetBlockVector()->Defragment(
      -
      14931  pBlockVectorCtx,
      -
      14932  pStats, flags,
      -
      14933  maxCpuBytesToMove, maxCpuAllocationsToMove,
      -
      14934  maxGpuBytesToMove, maxGpuAllocationsToMove,
      -
      14935  commandBuffer);
      -
      14936  if(pBlockVectorCtx->res != VK_SUCCESS)
      -
      14937  {
      -
      14938  res = pBlockVectorCtx->res;
      -
      14939  }
      -
      14940  }
      -
      14941  }
      -
      14942 
      -
      14943  // Process custom pools.
      -
      14944  for(size_t customCtxIndex = 0, customCtxCount = m_CustomPoolContexts.size();
      -
      14945  customCtxIndex < customCtxCount && res >= VK_SUCCESS;
      -
      14946  ++customCtxIndex)
      -
      14947  {
      -
      14948  VmaBlockVectorDefragmentationContext* pBlockVectorCtx = m_CustomPoolContexts[customCtxIndex];
      -
      14949  VMA_ASSERT(pBlockVectorCtx && pBlockVectorCtx->GetBlockVector());
      -
      14950  pBlockVectorCtx->GetBlockVector()->Defragment(
      -
      14951  pBlockVectorCtx,
      -
      14952  pStats, flags,
      -
      14953  maxCpuBytesToMove, maxCpuAllocationsToMove,
      -
      14954  maxGpuBytesToMove, maxGpuAllocationsToMove,
      -
      14955  commandBuffer);
      -
      14956  if(pBlockVectorCtx->res != VK_SUCCESS)
      -
      14957  {
      -
      14958  res = pBlockVectorCtx->res;
      -
      14959  }
      -
      14960  }
      -
      14961 
      -
      14962  return res;
      -
      14963 }
      -
      14964 
      -
      14965 VkResult VmaDefragmentationContext_T::DefragmentPassBegin(VmaDefragmentationPassInfo* pInfo)
      -
      14966 {
      -
      14967  VmaDefragmentationPassMoveInfo* pCurrentMove = pInfo->pMoves;
      -
      14968  uint32_t movesLeft = pInfo->moveCount;
      -
      14969 
      -
      14970  // Process default pools.
      -
      14971  for(uint32_t memTypeIndex = 0;
      -
      14972  memTypeIndex < m_hAllocator->GetMemoryTypeCount();
      -
      14973  ++memTypeIndex)
      -
      14974  {
      -
      14975  VmaBlockVectorDefragmentationContext *pBlockVectorCtx = m_DefaultPoolContexts[memTypeIndex];
      -
      14976  if(pBlockVectorCtx)
      -
      14977  {
      -
      14978  VMA_ASSERT(pBlockVectorCtx->GetBlockVector());
      -
      14979 
      -
      14980  if(!pBlockVectorCtx->hasDefragmentationPlan)
      -
      14981  {
      -
      14982  pBlockVectorCtx->GetBlockVector()->Defragment(
      -
      14983  pBlockVectorCtx,
      -
      14984  m_pStats, m_Flags,
      -
      14985  m_MaxCpuBytesToMove, m_MaxCpuAllocationsToMove,
      -
      14986  m_MaxGpuBytesToMove, m_MaxGpuAllocationsToMove,
      -
      14987  VK_NULL_HANDLE);
      -
      14988 
      -
      14989  if(pBlockVectorCtx->res < VK_SUCCESS)
      -
      14990  continue;
      -
      14991 
      -
      14992  pBlockVectorCtx->hasDefragmentationPlan = true;
      -
      14993  }
      -
      14994 
      -
      14995  const uint32_t processed = pBlockVectorCtx->GetBlockVector()->ProcessDefragmentations(
      -
      14996  pBlockVectorCtx,
      -
      14997  pCurrentMove, movesLeft);
      -
      14998 
      -
      14999  movesLeft -= processed;
      -
      15000  pCurrentMove += processed;
      -
      15001  }
      -
      15002  }
      -
      15003 
      -
      15004  // Process custom pools.
      -
      15005  for(size_t customCtxIndex = 0, customCtxCount = m_CustomPoolContexts.size();
      -
      15006  customCtxIndex < customCtxCount;
      -
      15007  ++customCtxIndex)
      -
      15008  {
      -
      15009  VmaBlockVectorDefragmentationContext *pBlockVectorCtx = m_CustomPoolContexts[customCtxIndex];
      -
      15010  VMA_ASSERT(pBlockVectorCtx && pBlockVectorCtx->GetBlockVector());
      -
      15011 
      -
      15012  if(!pBlockVectorCtx->hasDefragmentationPlan)
      -
      15013  {
      -
      15014  pBlockVectorCtx->GetBlockVector()->Defragment(
      -
      15015  pBlockVectorCtx,
      -
      15016  m_pStats, m_Flags,
      -
      15017  m_MaxCpuBytesToMove, m_MaxCpuAllocationsToMove,
      -
      15018  m_MaxGpuBytesToMove, m_MaxGpuAllocationsToMove,
      -
      15019  VK_NULL_HANDLE);
      -
      15020 
      -
      15021  if(pBlockVectorCtx->res < VK_SUCCESS)
      -
      15022  continue;
      -
      15023 
      -
      15024  pBlockVectorCtx->hasDefragmentationPlan = true;
      -
      15025  }
      -
      15026 
      -
      15027  const uint32_t processed = pBlockVectorCtx->GetBlockVector()->ProcessDefragmentations(
      -
      15028  pBlockVectorCtx,
      -
      15029  pCurrentMove, movesLeft);
      -
      15030 
      -
      15031  movesLeft -= processed;
      -
      15032  pCurrentMove += processed;
      -
      15033  }
      -
      15034 
      -
      15035  pInfo->moveCount = pInfo->moveCount - movesLeft;
      -
      15036 
      -
      15037  return VK_SUCCESS;
      -
      15038 }
      -
      15039 VkResult VmaDefragmentationContext_T::DefragmentPassEnd()
      -
      15040 {
      -
      15041  VkResult res = VK_SUCCESS;
      -
      15042 
      -
      15043  // Process default pools.
      -
      15044  for(uint32_t memTypeIndex = 0;
      -
      15045  memTypeIndex < m_hAllocator->GetMemoryTypeCount();
      -
      15046  ++memTypeIndex)
      -
      15047  {
      -
      15048  VmaBlockVectorDefragmentationContext *pBlockVectorCtx = m_DefaultPoolContexts[memTypeIndex];
      -
      15049  if(pBlockVectorCtx)
      -
      15050  {
      -
      15051  VMA_ASSERT(pBlockVectorCtx->GetBlockVector());
      -
      15052 
      -
      15053  if(!pBlockVectorCtx->hasDefragmentationPlan)
      -
      15054  {
      -
      15055  res = VK_NOT_READY;
      -
      15056  continue;
      -
      15057  }
      -
      15058 
      -
      15059  pBlockVectorCtx->GetBlockVector()->CommitDefragmentations(
      -
      15060  pBlockVectorCtx, m_pStats);
      -
      15061 
      -
      15062  if(pBlockVectorCtx->defragmentationMoves.size() != pBlockVectorCtx->defragmentationMovesCommitted)
      -
      15063  res = VK_NOT_READY;
      -
      15064  }
      -
      15065  }
      -
      15066 
      -
      15067  // Process custom pools.
      -
      15068  for(size_t customCtxIndex = 0, customCtxCount = m_CustomPoolContexts.size();
      -
      15069  customCtxIndex < customCtxCount;
      -
      15070  ++customCtxIndex)
      -
      15071  {
      -
      15072  VmaBlockVectorDefragmentationContext *pBlockVectorCtx = m_CustomPoolContexts[customCtxIndex];
      -
      15073  VMA_ASSERT(pBlockVectorCtx && pBlockVectorCtx->GetBlockVector());
      -
      15074 
      -
      15075  if(!pBlockVectorCtx->hasDefragmentationPlan)
      -
      15076  {
      -
      15077  res = VK_NOT_READY;
      -
      15078  continue;
      -
      15079  }
      -
      15080 
      -
      15081  pBlockVectorCtx->GetBlockVector()->CommitDefragmentations(
      -
      15082  pBlockVectorCtx, m_pStats);
      -
      15083 
      -
      15084  if(pBlockVectorCtx->defragmentationMoves.size() != pBlockVectorCtx->defragmentationMovesCommitted)
      -
      15085  res = VK_NOT_READY;
      -
      15086  }
      -
      15087 
      -
      15088  return res;
      -
      15089 }
      -
      15090 
      -
      15092 // VmaRecorder
      -
      15093 
      -
      15094 #if VMA_RECORDING_ENABLED
      -
      15095 
      -
      15096 VmaRecorder::VmaRecorder() :
      -
      15097  m_UseMutex(true),
      -
      15098  m_Flags(0),
      -
      15099  m_File(VMA_NULL),
      -
      15100  m_RecordingStartTime(std::chrono::high_resolution_clock::now())
      -
      15101 {
      -
      15102 }
      -
      15103 
      -
      15104 VkResult VmaRecorder::Init(const VmaRecordSettings& settings, bool useMutex)
      -
      15105 {
      -
      15106  m_UseMutex = useMutex;
      -
      15107  m_Flags = settings.flags;
      -
      15108 
      -
      15109 #if defined(_WIN32)
      -
      15110  // Open file for writing.
      -
      15111  errno_t err = fopen_s(&m_File, settings.pFilePath, "wb");
      -
      15112 
      -
      15113  if(err != 0)
      -
      15114  {
      -
      15115  return VK_ERROR_INITIALIZATION_FAILED;
      -
      15116  }
      -
      15117 #else
      -
      15118  // Open file for writing.
      -
      15119  m_File = fopen(settings.pFilePath, "wb");
      -
      15120 
      -
      15121  if(m_File == 0)
      -
      15122  {
      -
      15123  return VK_ERROR_INITIALIZATION_FAILED;
      -
      15124  }
      -
      15125 #endif
      -
      15126 
      -
      15127  // Write header.
      -
      15128  fprintf(m_File, "%s\n", "Vulkan Memory Allocator,Calls recording");
      -
      15129  fprintf(m_File, "%s\n", "1,8");
      -
      15130 
      -
      15131  return VK_SUCCESS;
      +
      14912  pMetadata->m_Suballocations.insert(it, suballoc);
      +
      14913 }
      +
      14914 
      +
      14916 // VmaBlockVectorDefragmentationContext
      +
      14917 
      +
      14918 VmaBlockVectorDefragmentationContext::VmaBlockVectorDefragmentationContext(
      +
      14919  VmaAllocator hAllocator,
      +
      14920  VmaPool hCustomPool,
      +
      14921  VmaBlockVector* pBlockVector,
      +
      14922  uint32_t currFrameIndex) :
      +
      14923  res(VK_SUCCESS),
      +
      14924  mutexLocked(false),
      +
      14925  blockContexts(VmaStlAllocator<VmaBlockDefragmentationContext>(hAllocator->GetAllocationCallbacks())),
      +
      14926  defragmentationMoves(VmaStlAllocator<VmaDefragmentationMove>(hAllocator->GetAllocationCallbacks())),
      +
      14927  defragmentationMovesProcessed(0),
      +
      14928  defragmentationMovesCommitted(0),
      +
      14929  hasDefragmentationPlan(0),
      +
      14930  m_hAllocator(hAllocator),
      +
      14931  m_hCustomPool(hCustomPool),
      +
      14932  m_pBlockVector(pBlockVector),
      +
      14933  m_CurrFrameIndex(currFrameIndex),
      +
      14934  m_pAlgorithm(VMA_NULL),
      +
      14935  m_Allocations(VmaStlAllocator<AllocInfo>(hAllocator->GetAllocationCallbacks())),
      +
      14936  m_AllAllocations(false)
      +
      14937 {
      +
      14938 }
      +
      14939 
      +
      14940 VmaBlockVectorDefragmentationContext::~VmaBlockVectorDefragmentationContext()
      +
      14941 {
      +
      14942  vma_delete(m_hAllocator, m_pAlgorithm);
      +
      14943 }
      +
      14944 
      +
      14945 void VmaBlockVectorDefragmentationContext::AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged)
      +
      14946 {
      +
      14947  AllocInfo info = { hAlloc, pChanged };
      +
      14948  m_Allocations.push_back(info);
      +
      14949 }
      +
      14950 
      +
      14951 void VmaBlockVectorDefragmentationContext::Begin(bool overlappingMoveSupported, VmaDefragmentationFlags flags)
      +
      14952 {
      +
      14953  const bool allAllocations = m_AllAllocations ||
      +
      14954  m_Allocations.size() == m_pBlockVector->CalcAllocationCount();
      +
      14955 
      +
      14956  /********************************
      +
      14957  HERE IS THE CHOICE OF DEFRAGMENTATION ALGORITHM.
      +
      14958  ********************************/
      +
      14959 
      +
      14960  /*
      +
      14961  Fast algorithm is supported only when certain criteria are met:
      +
      14962  - VMA_DEBUG_MARGIN is 0.
      +
      14963  - All allocations in this block vector are moveable.
      +
      14964  - There is no possibility of image/buffer granularity conflict.
      +
      14965  - The defragmentation is not incremental
      +
      14966  */
      +
      14967  if(VMA_DEBUG_MARGIN == 0 &&
      +
      14968  allAllocations &&
      +
      14969  !m_pBlockVector->IsBufferImageGranularityConflictPossible() &&
      + +
      14971  {
      +
      14972  m_pAlgorithm = vma_new(m_hAllocator, VmaDefragmentationAlgorithm_Fast)(
      +
      14973  m_hAllocator, m_pBlockVector, m_CurrFrameIndex, overlappingMoveSupported);
      +
      14974  }
      +
      14975  else
      +
      14976  {
      +
      14977  m_pAlgorithm = vma_new(m_hAllocator, VmaDefragmentationAlgorithm_Generic)(
      +
      14978  m_hAllocator, m_pBlockVector, m_CurrFrameIndex, overlappingMoveSupported);
      +
      14979  }
      +
      14980 
      +
      14981  if(allAllocations)
      +
      14982  {
      +
      14983  m_pAlgorithm->AddAll();
      +
      14984  }
      +
      14985  else
      +
      14986  {
      +
      14987  for(size_t i = 0, count = m_Allocations.size(); i < count; ++i)
      +
      14988  {
      +
      14989  m_pAlgorithm->AddAllocation(m_Allocations[i].hAlloc, m_Allocations[i].pChanged);
      +
      14990  }
      +
      14991  }
      +
      14992 }
      +
      14993 
      +
      14995 // VmaDefragmentationContext
      +
      14996 
      +
      14997 VmaDefragmentationContext_T::VmaDefragmentationContext_T(
      +
      14998  VmaAllocator hAllocator,
      +
      14999  uint32_t currFrameIndex,
      +
      15000  uint32_t flags,
      +
      15001  VmaDefragmentationStats* pStats) :
      +
      15002  m_hAllocator(hAllocator),
      +
      15003  m_CurrFrameIndex(currFrameIndex),
      +
      15004  m_Flags(flags),
      +
      15005  m_pStats(pStats),
      +
      15006  m_CustomPoolContexts(VmaStlAllocator<VmaBlockVectorDefragmentationContext*>(hAllocator->GetAllocationCallbacks()))
      +
      15007 {
      +
      15008  memset(m_DefaultPoolContexts, 0, sizeof(m_DefaultPoolContexts));
      +
      15009 }
      +
      15010 
      +
      15011 VmaDefragmentationContext_T::~VmaDefragmentationContext_T()
      +
      15012 {
      +
      15013  for(size_t i = m_CustomPoolContexts.size(); i--; )
      +
      15014  {
      +
      15015  VmaBlockVectorDefragmentationContext* pBlockVectorCtx = m_CustomPoolContexts[i];
      +
      15016  pBlockVectorCtx->GetBlockVector()->DefragmentationEnd(pBlockVectorCtx, m_Flags, m_pStats);
      +
      15017  vma_delete(m_hAllocator, pBlockVectorCtx);
      +
      15018  }
      +
      15019  for(size_t i = m_hAllocator->m_MemProps.memoryTypeCount; i--; )
      +
      15020  {
      +
      15021  VmaBlockVectorDefragmentationContext* pBlockVectorCtx = m_DefaultPoolContexts[i];
      +
      15022  if(pBlockVectorCtx)
      +
      15023  {
      +
      15024  pBlockVectorCtx->GetBlockVector()->DefragmentationEnd(pBlockVectorCtx, m_Flags, m_pStats);
      +
      15025  vma_delete(m_hAllocator, pBlockVectorCtx);
      +
      15026  }
      +
      15027  }
      +
      15028 }
      +
      15029 
      +
      15030 void VmaDefragmentationContext_T::AddPools(uint32_t poolCount, const VmaPool* pPools)
      +
      15031 {
      +
      15032  for(uint32_t poolIndex = 0; poolIndex < poolCount; ++poolIndex)
      +
      15033  {
      +
      15034  VmaPool pool = pPools[poolIndex];
      +
      15035  VMA_ASSERT(pool);
      +
      15036  // Pools with algorithm other than default are not defragmented.
      +
      15037  if(pool->m_BlockVector.GetAlgorithm() == 0)
      +
      15038  {
      +
      15039  VmaBlockVectorDefragmentationContext* pBlockVectorDefragCtx = VMA_NULL;
      +
      15040 
      +
      15041  for(size_t i = m_CustomPoolContexts.size(); i--; )
      +
      15042  {
      +
      15043  if(m_CustomPoolContexts[i]->GetCustomPool() == pool)
      +
      15044  {
      +
      15045  pBlockVectorDefragCtx = m_CustomPoolContexts[i];
      +
      15046  break;
      +
      15047  }
      +
      15048  }
      +
      15049 
      +
      15050  if(!pBlockVectorDefragCtx)
      +
      15051  {
      +
      15052  pBlockVectorDefragCtx = vma_new(m_hAllocator, VmaBlockVectorDefragmentationContext)(
      +
      15053  m_hAllocator,
      +
      15054  pool,
      +
      15055  &pool->m_BlockVector,
      +
      15056  m_CurrFrameIndex);
      +
      15057  m_CustomPoolContexts.push_back(pBlockVectorDefragCtx);
      +
      15058  }
      +
      15059 
      +
      15060  pBlockVectorDefragCtx->AddAll();
      +
      15061  }
      +
      15062  }
      +
      15063 }
      +
      15064 
      +
      15065 void VmaDefragmentationContext_T::AddAllocations(
      +
      15066  uint32_t allocationCount,
      +
      15067  const VmaAllocation* pAllocations,
      +
      15068  VkBool32* pAllocationsChanged)
      +
      15069 {
      +
      15070  // Dispatch pAllocations among defragmentators. Create them when necessary.
      +
      15071  for(uint32_t allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
      +
      15072  {
      +
      15073  const VmaAllocation hAlloc = pAllocations[allocIndex];
      +
      15074  VMA_ASSERT(hAlloc);
      +
      15075  // DedicatedAlloc cannot be defragmented.
      +
      15076  if((hAlloc->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK) &&
      +
      15077  // Lost allocation cannot be defragmented.
      +
      15078  (hAlloc->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST))
      +
      15079  {
      +
      15080  VmaBlockVectorDefragmentationContext* pBlockVectorDefragCtx = VMA_NULL;
      +
      15081 
      +
      15082  const VmaPool hAllocPool = hAlloc->GetBlock()->GetParentPool();
      +
      15083  // This allocation belongs to custom pool.
      +
      15084  if(hAllocPool != VK_NULL_HANDLE)
      +
      15085  {
      +
      15086  // Pools with algorithm other than default are not defragmented.
      +
      15087  if(hAllocPool->m_BlockVector.GetAlgorithm() == 0)
      +
      15088  {
      +
      15089  for(size_t i = m_CustomPoolContexts.size(); i--; )
      +
      15090  {
      +
      15091  if(m_CustomPoolContexts[i]->GetCustomPool() == hAllocPool)
      +
      15092  {
      +
      15093  pBlockVectorDefragCtx = m_CustomPoolContexts[i];
      +
      15094  break;
      +
      15095  }
      +
      15096  }
      +
      15097  if(!pBlockVectorDefragCtx)
      +
      15098  {
      +
      15099  pBlockVectorDefragCtx = vma_new(m_hAllocator, VmaBlockVectorDefragmentationContext)(
      +
      15100  m_hAllocator,
      +
      15101  hAllocPool,
      +
      15102  &hAllocPool->m_BlockVector,
      +
      15103  m_CurrFrameIndex);
      +
      15104  m_CustomPoolContexts.push_back(pBlockVectorDefragCtx);
      +
      15105  }
      +
      15106  }
      +
      15107  }
      +
      15108  // This allocation belongs to default pool.
      +
      15109  else
      +
      15110  {
      +
      15111  const uint32_t memTypeIndex = hAlloc->GetMemoryTypeIndex();
      +
      15112  pBlockVectorDefragCtx = m_DefaultPoolContexts[memTypeIndex];
      +
      15113  if(!pBlockVectorDefragCtx)
      +
      15114  {
      +
      15115  pBlockVectorDefragCtx = vma_new(m_hAllocator, VmaBlockVectorDefragmentationContext)(
      +
      15116  m_hAllocator,
      +
      15117  VMA_NULL, // hCustomPool
      +
      15118  m_hAllocator->m_pBlockVectors[memTypeIndex],
      +
      15119  m_CurrFrameIndex);
      +
      15120  m_DefaultPoolContexts[memTypeIndex] = pBlockVectorDefragCtx;
      +
      15121  }
      +
      15122  }
      +
      15123 
      +
      15124  if(pBlockVectorDefragCtx)
      +
      15125  {
      +
      15126  VkBool32* const pChanged = (pAllocationsChanged != VMA_NULL) ?
      +
      15127  &pAllocationsChanged[allocIndex] : VMA_NULL;
      +
      15128  pBlockVectorDefragCtx->AddAllocation(hAlloc, pChanged);
      +
      15129  }
      +
      15130  }
      +
      15131  }
      15132 }
      15133 
      -
      15134 VmaRecorder::~VmaRecorder()
      -
      15135 {
      -
      15136  if(m_File != VMA_NULL)
      -
      15137  {
      -
      15138  fclose(m_File);
      -
      15139  }
      -
      15140 }
      -
      15141 
      -
      15142 void VmaRecorder::RecordCreateAllocator(uint32_t frameIndex)
      -
      15143 {
      -
      15144  CallParams callParams;
      -
      15145  GetBasicParams(callParams);
      -
      15146 
      -
      15147  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15148  fprintf(m_File, "%u,%.3f,%u,vmaCreateAllocator\n", callParams.threadId, callParams.time, frameIndex);
      -
      15149  Flush();
      -
      15150 }
      -
      15151 
      -
      15152 void VmaRecorder::RecordDestroyAllocator(uint32_t frameIndex)
      -
      15153 {
      -
      15154  CallParams callParams;
      -
      15155  GetBasicParams(callParams);
      -
      15156 
      -
      15157  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15158  fprintf(m_File, "%u,%.3f,%u,vmaDestroyAllocator\n", callParams.threadId, callParams.time, frameIndex);
      -
      15159  Flush();
      -
      15160 }
      -
      15161 
      -
      15162 void VmaRecorder::RecordCreatePool(uint32_t frameIndex, const VmaPoolCreateInfo& createInfo, VmaPool pool)
      -
      15163 {
      -
      15164  CallParams callParams;
      -
      15165  GetBasicParams(callParams);
      +
      15134 VkResult VmaDefragmentationContext_T::Defragment(
      +
      15135  VkDeviceSize maxCpuBytesToMove, uint32_t maxCpuAllocationsToMove,
      +
      15136  VkDeviceSize maxGpuBytesToMove, uint32_t maxGpuAllocationsToMove,
      +
      15137  VkCommandBuffer commandBuffer, VmaDefragmentationStats* pStats, VmaDefragmentationFlags flags)
      +
      15138 {
      +
      15139  if(pStats)
      +
      15140  {
      +
      15141  memset(pStats, 0, sizeof(VmaDefragmentationStats));
      +
      15142  }
      +
      15143 
      + +
      15145  {
      +
      15146  // For incremental defragmetnations, we just earmark how much we can move
      +
      15147  // The real meat is in the defragmentation steps
      +
      15148  m_MaxCpuBytesToMove = maxCpuBytesToMove;
      +
      15149  m_MaxCpuAllocationsToMove = maxCpuAllocationsToMove;
      +
      15150 
      +
      15151  m_MaxGpuBytesToMove = maxGpuBytesToMove;
      +
      15152  m_MaxGpuAllocationsToMove = maxGpuAllocationsToMove;
      +
      15153 
      +
      15154  if(m_MaxCpuBytesToMove == 0 && m_MaxCpuAllocationsToMove == 0 &&
      +
      15155  m_MaxGpuBytesToMove == 0 && m_MaxGpuAllocationsToMove == 0)
      +
      15156  return VK_SUCCESS;
      +
      15157 
      +
      15158  return VK_NOT_READY;
      +
      15159  }
      +
      15160 
      +
      15161  if(commandBuffer == VK_NULL_HANDLE)
      +
      15162  {
      +
      15163  maxGpuBytesToMove = 0;
      +
      15164  maxGpuAllocationsToMove = 0;
      +
      15165  }
      15166 
      -
      15167  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15168  fprintf(m_File, "%u,%.3f,%u,vmaCreatePool,%u,%u,%llu,%llu,%llu,%u,%p\n", callParams.threadId, callParams.time, frameIndex,
      -
      15169  createInfo.memoryTypeIndex,
      -
      15170  createInfo.flags,
      -
      15171  createInfo.blockSize,
      -
      15172  (uint64_t)createInfo.minBlockCount,
      -
      15173  (uint64_t)createInfo.maxBlockCount,
      -
      15174  createInfo.frameInUseCount,
      -
      15175  pool);
      -
      15176  Flush();
      -
      15177 }
      -
      15178 
      -
      15179 void VmaRecorder::RecordDestroyPool(uint32_t frameIndex, VmaPool pool)
      -
      15180 {
      -
      15181  CallParams callParams;
      -
      15182  GetBasicParams(callParams);
      -
      15183 
      -
      15184  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15185  fprintf(m_File, "%u,%.3f,%u,vmaDestroyPool,%p\n", callParams.threadId, callParams.time, frameIndex,
      -
      15186  pool);
      -
      15187  Flush();
      -
      15188 }
      -
      15189 
      -
      15190 void VmaRecorder::RecordAllocateMemory(uint32_t frameIndex,
      -
      15191  const VkMemoryRequirements& vkMemReq,
      -
      15192  const VmaAllocationCreateInfo& createInfo,
      -
      15193  VmaAllocation allocation)
      -
      15194 {
      -
      15195  CallParams callParams;
      -
      15196  GetBasicParams(callParams);
      -
      15197 
      -
      15198  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15199  UserDataString userDataStr(createInfo.flags, createInfo.pUserData);
      -
      15200  fprintf(m_File, "%u,%.3f,%u,vmaAllocateMemory,%llu,%llu,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
      -
      15201  vkMemReq.size,
      -
      15202  vkMemReq.alignment,
      -
      15203  vkMemReq.memoryTypeBits,
      -
      15204  createInfo.flags,
      -
      15205  createInfo.usage,
      -
      15206  createInfo.requiredFlags,
      -
      15207  createInfo.preferredFlags,
      -
      15208  createInfo.memoryTypeBits,
      -
      15209  createInfo.pool,
      -
      15210  allocation,
      -
      15211  userDataStr.GetString());
      -
      15212  Flush();
      -
      15213 }
      -
      15214 
      -
      15215 void VmaRecorder::RecordAllocateMemoryPages(uint32_t frameIndex,
      -
      15216  const VkMemoryRequirements& vkMemReq,
      -
      15217  const VmaAllocationCreateInfo& createInfo,
      -
      15218  uint64_t allocationCount,
      -
      15219  const VmaAllocation* pAllocations)
      -
      15220 {
      -
      15221  CallParams callParams;
      -
      15222  GetBasicParams(callParams);
      -
      15223 
      -
      15224  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15225  UserDataString userDataStr(createInfo.flags, createInfo.pUserData);
      -
      15226  fprintf(m_File, "%u,%.3f,%u,vmaAllocateMemoryPages,%llu,%llu,%u,%u,%u,%u,%u,%u,%p,", callParams.threadId, callParams.time, frameIndex,
      -
      15227  vkMemReq.size,
      -
      15228  vkMemReq.alignment,
      -
      15229  vkMemReq.memoryTypeBits,
      -
      15230  createInfo.flags,
      -
      15231  createInfo.usage,
      -
      15232  createInfo.requiredFlags,
      -
      15233  createInfo.preferredFlags,
      -
      15234  createInfo.memoryTypeBits,
      -
      15235  createInfo.pool);
      -
      15236  PrintPointerList(allocationCount, pAllocations);
      -
      15237  fprintf(m_File, ",%s\n", userDataStr.GetString());
      -
      15238  Flush();
      -
      15239 }
      -
      15240 
      -
      15241 void VmaRecorder::RecordAllocateMemoryForBuffer(uint32_t frameIndex,
      -
      15242  const VkMemoryRequirements& vkMemReq,
      -
      15243  bool requiresDedicatedAllocation,
      -
      15244  bool prefersDedicatedAllocation,
      -
      15245  const VmaAllocationCreateInfo& createInfo,
      -
      15246  VmaAllocation allocation)
      -
      15247 {
      -
      15248  CallParams callParams;
      -
      15249  GetBasicParams(callParams);
      -
      15250 
      -
      15251  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15252  UserDataString userDataStr(createInfo.flags, createInfo.pUserData);
      -
      15253  fprintf(m_File, "%u,%.3f,%u,vmaAllocateMemoryForBuffer,%llu,%llu,%u,%u,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
      -
      15254  vkMemReq.size,
      -
      15255  vkMemReq.alignment,
      -
      15256  vkMemReq.memoryTypeBits,
      -
      15257  requiresDedicatedAllocation ? 1 : 0,
      -
      15258  prefersDedicatedAllocation ? 1 : 0,
      -
      15259  createInfo.flags,
      -
      15260  createInfo.usage,
      -
      15261  createInfo.requiredFlags,
      -
      15262  createInfo.preferredFlags,
      -
      15263  createInfo.memoryTypeBits,
      -
      15264  createInfo.pool,
      -
      15265  allocation,
      -
      15266  userDataStr.GetString());
      -
      15267  Flush();
      -
      15268 }
      -
      15269 
      -
      15270 void VmaRecorder::RecordAllocateMemoryForImage(uint32_t frameIndex,
      -
      15271  const VkMemoryRequirements& vkMemReq,
      -
      15272  bool requiresDedicatedAllocation,
      -
      15273  bool prefersDedicatedAllocation,
      -
      15274  const VmaAllocationCreateInfo& createInfo,
      -
      15275  VmaAllocation allocation)
      -
      15276 {
      -
      15277  CallParams callParams;
      -
      15278  GetBasicParams(callParams);
      -
      15279 
      -
      15280  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15281  UserDataString userDataStr(createInfo.flags, createInfo.pUserData);
      -
      15282  fprintf(m_File, "%u,%.3f,%u,vmaAllocateMemoryForImage,%llu,%llu,%u,%u,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
      -
      15283  vkMemReq.size,
      -
      15284  vkMemReq.alignment,
      -
      15285  vkMemReq.memoryTypeBits,
      -
      15286  requiresDedicatedAllocation ? 1 : 0,
      -
      15287  prefersDedicatedAllocation ? 1 : 0,
      -
      15288  createInfo.flags,
      -
      15289  createInfo.usage,
      -
      15290  createInfo.requiredFlags,
      -
      15291  createInfo.preferredFlags,
      -
      15292  createInfo.memoryTypeBits,
      -
      15293  createInfo.pool,
      -
      15294  allocation,
      -
      15295  userDataStr.GetString());
      -
      15296  Flush();
      -
      15297 }
      -
      15298 
      -
      15299 void VmaRecorder::RecordFreeMemory(uint32_t frameIndex,
      -
      15300  VmaAllocation allocation)
      -
      15301 {
      -
      15302  CallParams callParams;
      -
      15303  GetBasicParams(callParams);
      -
      15304 
      -
      15305  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15306  fprintf(m_File, "%u,%.3f,%u,vmaFreeMemory,%p\n", callParams.threadId, callParams.time, frameIndex,
      -
      15307  allocation);
      -
      15308  Flush();
      -
      15309 }
      -
      15310 
      -
      15311 void VmaRecorder::RecordFreeMemoryPages(uint32_t frameIndex,
      -
      15312  uint64_t allocationCount,
      -
      15313  const VmaAllocation* pAllocations)
      -
      15314 {
      -
      15315  CallParams callParams;
      -
      15316  GetBasicParams(callParams);
      -
      15317 
      -
      15318  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15319  fprintf(m_File, "%u,%.3f,%u,vmaFreeMemoryPages,", callParams.threadId, callParams.time, frameIndex);
      -
      15320  PrintPointerList(allocationCount, pAllocations);
      -
      15321  fprintf(m_File, "\n");
      -
      15322  Flush();
      -
      15323 }
      -
      15324 
      -
      15325 void VmaRecorder::RecordSetAllocationUserData(uint32_t frameIndex,
      -
      15326  VmaAllocation allocation,
      -
      15327  const void* pUserData)
      -
      15328 {
      -
      15329  CallParams callParams;
      -
      15330  GetBasicParams(callParams);
      +
      15167  VkResult res = VK_SUCCESS;
      +
      15168 
      +
      15169  // Process default pools.
      +
      15170  for(uint32_t memTypeIndex = 0;
      +
      15171  memTypeIndex < m_hAllocator->GetMemoryTypeCount() && res >= VK_SUCCESS;
      +
      15172  ++memTypeIndex)
      +
      15173  {
      +
      15174  VmaBlockVectorDefragmentationContext* pBlockVectorCtx = m_DefaultPoolContexts[memTypeIndex];
      +
      15175  if(pBlockVectorCtx)
      +
      15176  {
      +
      15177  VMA_ASSERT(pBlockVectorCtx->GetBlockVector());
      +
      15178  pBlockVectorCtx->GetBlockVector()->Defragment(
      +
      15179  pBlockVectorCtx,
      +
      15180  pStats, flags,
      +
      15181  maxCpuBytesToMove, maxCpuAllocationsToMove,
      +
      15182  maxGpuBytesToMove, maxGpuAllocationsToMove,
      +
      15183  commandBuffer);
      +
      15184  if(pBlockVectorCtx->res != VK_SUCCESS)
      +
      15185  {
      +
      15186  res = pBlockVectorCtx->res;
      +
      15187  }
      +
      15188  }
      +
      15189  }
      +
      15190 
      +
      15191  // Process custom pools.
      +
      15192  for(size_t customCtxIndex = 0, customCtxCount = m_CustomPoolContexts.size();
      +
      15193  customCtxIndex < customCtxCount && res >= VK_SUCCESS;
      +
      15194  ++customCtxIndex)
      +
      15195  {
      +
      15196  VmaBlockVectorDefragmentationContext* pBlockVectorCtx = m_CustomPoolContexts[customCtxIndex];
      +
      15197  VMA_ASSERT(pBlockVectorCtx && pBlockVectorCtx->GetBlockVector());
      +
      15198  pBlockVectorCtx->GetBlockVector()->Defragment(
      +
      15199  pBlockVectorCtx,
      +
      15200  pStats, flags,
      +
      15201  maxCpuBytesToMove, maxCpuAllocationsToMove,
      +
      15202  maxGpuBytesToMove, maxGpuAllocationsToMove,
      +
      15203  commandBuffer);
      +
      15204  if(pBlockVectorCtx->res != VK_SUCCESS)
      +
      15205  {
      +
      15206  res = pBlockVectorCtx->res;
      +
      15207  }
      +
      15208  }
      +
      15209 
      +
      15210  return res;
      +
      15211 }
      +
      15212 
      +
      15213 VkResult VmaDefragmentationContext_T::DefragmentPassBegin(VmaDefragmentationPassInfo* pInfo)
      +
      15214 {
      +
      15215  VmaDefragmentationPassMoveInfo* pCurrentMove = pInfo->pMoves;
      +
      15216  uint32_t movesLeft = pInfo->moveCount;
      +
      15217 
      +
      15218  // Process default pools.
      +
      15219  for(uint32_t memTypeIndex = 0;
      +
      15220  memTypeIndex < m_hAllocator->GetMemoryTypeCount();
      +
      15221  ++memTypeIndex)
      +
      15222  {
      +
      15223  VmaBlockVectorDefragmentationContext *pBlockVectorCtx = m_DefaultPoolContexts[memTypeIndex];
      +
      15224  if(pBlockVectorCtx)
      +
      15225  {
      +
      15226  VMA_ASSERT(pBlockVectorCtx->GetBlockVector());
      +
      15227 
      +
      15228  if(!pBlockVectorCtx->hasDefragmentationPlan)
      +
      15229  {
      +
      15230  pBlockVectorCtx->GetBlockVector()->Defragment(
      +
      15231  pBlockVectorCtx,
      +
      15232  m_pStats, m_Flags,
      +
      15233  m_MaxCpuBytesToMove, m_MaxCpuAllocationsToMove,
      +
      15234  m_MaxGpuBytesToMove, m_MaxGpuAllocationsToMove,
      +
      15235  VK_NULL_HANDLE);
      +
      15236 
      +
      15237  if(pBlockVectorCtx->res < VK_SUCCESS)
      +
      15238  continue;
      +
      15239 
      +
      15240  pBlockVectorCtx->hasDefragmentationPlan = true;
      +
      15241  }
      +
      15242 
      +
      15243  const uint32_t processed = pBlockVectorCtx->GetBlockVector()->ProcessDefragmentations(
      +
      15244  pBlockVectorCtx,
      +
      15245  pCurrentMove, movesLeft);
      +
      15246 
      +
      15247  movesLeft -= processed;
      +
      15248  pCurrentMove += processed;
      +
      15249  }
      +
      15250  }
      +
      15251 
      +
      15252  // Process custom pools.
      +
      15253  for(size_t customCtxIndex = 0, customCtxCount = m_CustomPoolContexts.size();
      +
      15254  customCtxIndex < customCtxCount;
      +
      15255  ++customCtxIndex)
      +
      15256  {
      +
      15257  VmaBlockVectorDefragmentationContext *pBlockVectorCtx = m_CustomPoolContexts[customCtxIndex];
      +
      15258  VMA_ASSERT(pBlockVectorCtx && pBlockVectorCtx->GetBlockVector());
      +
      15259 
      +
      15260  if(!pBlockVectorCtx->hasDefragmentationPlan)
      +
      15261  {
      +
      15262  pBlockVectorCtx->GetBlockVector()->Defragment(
      +
      15263  pBlockVectorCtx,
      +
      15264  m_pStats, m_Flags,
      +
      15265  m_MaxCpuBytesToMove, m_MaxCpuAllocationsToMove,
      +
      15266  m_MaxGpuBytesToMove, m_MaxGpuAllocationsToMove,
      +
      15267  VK_NULL_HANDLE);
      +
      15268 
      +
      15269  if(pBlockVectorCtx->res < VK_SUCCESS)
      +
      15270  continue;
      +
      15271 
      +
      15272  pBlockVectorCtx->hasDefragmentationPlan = true;
      +
      15273  }
      +
      15274 
      +
      15275  const uint32_t processed = pBlockVectorCtx->GetBlockVector()->ProcessDefragmentations(
      +
      15276  pBlockVectorCtx,
      +
      15277  pCurrentMove, movesLeft);
      +
      15278 
      +
      15279  movesLeft -= processed;
      +
      15280  pCurrentMove += processed;
      +
      15281  }
      +
      15282 
      +
      15283  pInfo->moveCount = pInfo->moveCount - movesLeft;
      +
      15284 
      +
      15285  return VK_SUCCESS;
      +
      15286 }
      +
      15287 VkResult VmaDefragmentationContext_T::DefragmentPassEnd()
      +
      15288 {
      +
      15289  VkResult res = VK_SUCCESS;
      +
      15290 
      +
      15291  // Process default pools.
      +
      15292  for(uint32_t memTypeIndex = 0;
      +
      15293  memTypeIndex < m_hAllocator->GetMemoryTypeCount();
      +
      15294  ++memTypeIndex)
      +
      15295  {
      +
      15296  VmaBlockVectorDefragmentationContext *pBlockVectorCtx = m_DefaultPoolContexts[memTypeIndex];
      +
      15297  if(pBlockVectorCtx)
      +
      15298  {
      +
      15299  VMA_ASSERT(pBlockVectorCtx->GetBlockVector());
      +
      15300 
      +
      15301  if(!pBlockVectorCtx->hasDefragmentationPlan)
      +
      15302  {
      +
      15303  res = VK_NOT_READY;
      +
      15304  continue;
      +
      15305  }
      +
      15306 
      +
      15307  pBlockVectorCtx->GetBlockVector()->CommitDefragmentations(
      +
      15308  pBlockVectorCtx, m_pStats);
      +
      15309 
      +
      15310  if(pBlockVectorCtx->defragmentationMoves.size() != pBlockVectorCtx->defragmentationMovesCommitted)
      +
      15311  res = VK_NOT_READY;
      +
      15312  }
      +
      15313  }
      +
      15314 
      +
      15315  // Process custom pools.
      +
      15316  for(size_t customCtxIndex = 0, customCtxCount = m_CustomPoolContexts.size();
      +
      15317  customCtxIndex < customCtxCount;
      +
      15318  ++customCtxIndex)
      +
      15319  {
      +
      15320  VmaBlockVectorDefragmentationContext *pBlockVectorCtx = m_CustomPoolContexts[customCtxIndex];
      +
      15321  VMA_ASSERT(pBlockVectorCtx && pBlockVectorCtx->GetBlockVector());
      +
      15322 
      +
      15323  if(!pBlockVectorCtx->hasDefragmentationPlan)
      +
      15324  {
      +
      15325  res = VK_NOT_READY;
      +
      15326  continue;
      +
      15327  }
      +
      15328 
      +
      15329  pBlockVectorCtx->GetBlockVector()->CommitDefragmentations(
      +
      15330  pBlockVectorCtx, m_pStats);
      15331 
      -
      15332  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15333  UserDataString userDataStr(
      -
      15334  allocation->IsUserDataString() ? VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT : 0,
      -
      15335  pUserData);
      -
      15336  fprintf(m_File, "%u,%.3f,%u,vmaSetAllocationUserData,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
      -
      15337  allocation,
      -
      15338  userDataStr.GetString());
      -
      15339  Flush();
      -
      15340 }
      +
      15332  if(pBlockVectorCtx->defragmentationMoves.size() != pBlockVectorCtx->defragmentationMovesCommitted)
      +
      15333  res = VK_NOT_READY;
      +
      15334  }
      +
      15335 
      +
      15336  return res;
      +
      15337 }
      +
      15338 
      +
      15340 // VmaRecorder
      15341 
      -
      15342 void VmaRecorder::RecordCreateLostAllocation(uint32_t frameIndex,
      -
      15343  VmaAllocation allocation)
      -
      15344 {
      -
      15345  CallParams callParams;
      -
      15346  GetBasicParams(callParams);
      -
      15347 
      -
      15348  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15349  fprintf(m_File, "%u,%.3f,%u,vmaCreateLostAllocation,%p\n", callParams.threadId, callParams.time, frameIndex,
      -
      15350  allocation);
      -
      15351  Flush();
      -
      15352 }
      -
      15353 
      -
      15354 void VmaRecorder::RecordMapMemory(uint32_t frameIndex,
      -
      15355  VmaAllocation allocation)
      -
      15356 {
      -
      15357  CallParams callParams;
      -
      15358  GetBasicParams(callParams);
      -
      15359 
      -
      15360  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15361  fprintf(m_File, "%u,%.3f,%u,vmaMapMemory,%p\n", callParams.threadId, callParams.time, frameIndex,
      -
      15362  allocation);
      -
      15363  Flush();
      -
      15364 }
      -
      15365 
      -
      15366 void VmaRecorder::RecordUnmapMemory(uint32_t frameIndex,
      -
      15367  VmaAllocation allocation)
      -
      15368 {
      -
      15369  CallParams callParams;
      -
      15370  GetBasicParams(callParams);
      -
      15371 
      -
      15372  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15373  fprintf(m_File, "%u,%.3f,%u,vmaUnmapMemory,%p\n", callParams.threadId, callParams.time, frameIndex,
      -
      15374  allocation);
      -
      15375  Flush();
      -
      15376 }
      -
      15377 
      -
      15378 void VmaRecorder::RecordFlushAllocation(uint32_t frameIndex,
      -
      15379  VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size)
      -
      15380 {
      -
      15381  CallParams callParams;
      -
      15382  GetBasicParams(callParams);
      -
      15383 
      -
      15384  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15385  fprintf(m_File, "%u,%.3f,%u,vmaFlushAllocation,%p,%llu,%llu\n", callParams.threadId, callParams.time, frameIndex,
      -
      15386  allocation,
      -
      15387  offset,
      -
      15388  size);
      -
      15389  Flush();
      -
      15390 }
      -
      15391 
      -
      15392 void VmaRecorder::RecordInvalidateAllocation(uint32_t frameIndex,
      -
      15393  VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size)
      -
      15394 {
      -
      15395  CallParams callParams;
      -
      15396  GetBasicParams(callParams);
      -
      15397 
      -
      15398  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15399  fprintf(m_File, "%u,%.3f,%u,vmaInvalidateAllocation,%p,%llu,%llu\n", callParams.threadId, callParams.time, frameIndex,
      -
      15400  allocation,
      -
      15401  offset,
      -
      15402  size);
      -
      15403  Flush();
      -
      15404 }
      -
      15405 
      -
      15406 void VmaRecorder::RecordCreateBuffer(uint32_t frameIndex,
      -
      15407  const VkBufferCreateInfo& bufCreateInfo,
      -
      15408  const VmaAllocationCreateInfo& allocCreateInfo,
      -
      15409  VmaAllocation allocation)
      -
      15410 {
      -
      15411  CallParams callParams;
      -
      15412  GetBasicParams(callParams);
      -
      15413 
      -
      15414  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15415  UserDataString userDataStr(allocCreateInfo.flags, allocCreateInfo.pUserData);
      -
      15416  fprintf(m_File, "%u,%.3f,%u,vmaCreateBuffer,%u,%llu,%u,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
      -
      15417  bufCreateInfo.flags,
      -
      15418  bufCreateInfo.size,
      -
      15419  bufCreateInfo.usage,
      -
      15420  bufCreateInfo.sharingMode,
      -
      15421  allocCreateInfo.flags,
      -
      15422  allocCreateInfo.usage,
      -
      15423  allocCreateInfo.requiredFlags,
      -
      15424  allocCreateInfo.preferredFlags,
      -
      15425  allocCreateInfo.memoryTypeBits,
      -
      15426  allocCreateInfo.pool,
      -
      15427  allocation,
      -
      15428  userDataStr.GetString());
      -
      15429  Flush();
      -
      15430 }
      +
      15342 #if VMA_RECORDING_ENABLED
      +
      15343 
      +
      15344 VmaRecorder::VmaRecorder() :
      +
      15345  m_UseMutex(true),
      +
      15346  m_Flags(0),
      +
      15347  m_File(VMA_NULL),
      +
      15348  m_RecordingStartTime(std::chrono::high_resolution_clock::now())
      +
      15349 {
      +
      15350 }
      +
      15351 
      +
      15352 VkResult VmaRecorder::Init(const VmaRecordSettings& settings, bool useMutex)
      +
      15353 {
      +
      15354  m_UseMutex = useMutex;
      +
      15355  m_Flags = settings.flags;
      +
      15356 
      +
      15357 #if defined(_WIN32)
      +
      15358  // Open file for writing.
      +
      15359  errno_t err = fopen_s(&m_File, settings.pFilePath, "wb");
      +
      15360 
      +
      15361  if(err != 0)
      +
      15362  {
      +
      15363  return VK_ERROR_INITIALIZATION_FAILED;
      +
      15364  }
      +
      15365 #else
      +
      15366  // Open file for writing.
      +
      15367  m_File = fopen(settings.pFilePath, "wb");
      +
      15368 
      +
      15369  if(m_File == 0)
      +
      15370  {
      +
      15371  return VK_ERROR_INITIALIZATION_FAILED;
      +
      15372  }
      +
      15373 #endif
      +
      15374 
      +
      15375  // Write header.
      +
      15376  fprintf(m_File, "%s\n", "Vulkan Memory Allocator,Calls recording");
      +
      15377  fprintf(m_File, "%s\n", "1,8");
      +
      15378 
      +
      15379  return VK_SUCCESS;
      +
      15380 }
      +
      15381 
      +
      15382 VmaRecorder::~VmaRecorder()
      +
      15383 {
      +
      15384  if(m_File != VMA_NULL)
      +
      15385  {
      +
      15386  fclose(m_File);
      +
      15387  }
      +
      15388 }
      +
      15389 
      +
      15390 void VmaRecorder::RecordCreateAllocator(uint32_t frameIndex)
      +
      15391 {
      +
      15392  CallParams callParams;
      +
      15393  GetBasicParams(callParams);
      +
      15394 
      +
      15395  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15396  fprintf(m_File, "%u,%.3f,%u,vmaCreateAllocator\n", callParams.threadId, callParams.time, frameIndex);
      +
      15397  Flush();
      +
      15398 }
      +
      15399 
      +
      15400 void VmaRecorder::RecordDestroyAllocator(uint32_t frameIndex)
      +
      15401 {
      +
      15402  CallParams callParams;
      +
      15403  GetBasicParams(callParams);
      +
      15404 
      +
      15405  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15406  fprintf(m_File, "%u,%.3f,%u,vmaDestroyAllocator\n", callParams.threadId, callParams.time, frameIndex);
      +
      15407  Flush();
      +
      15408 }
      +
      15409 
      +
      15410 void VmaRecorder::RecordCreatePool(uint32_t frameIndex, const VmaPoolCreateInfo& createInfo, VmaPool pool)
      +
      15411 {
      +
      15412  CallParams callParams;
      +
      15413  GetBasicParams(callParams);
      +
      15414 
      +
      15415  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15416  fprintf(m_File, "%u,%.3f,%u,vmaCreatePool,%u,%u,%llu,%llu,%llu,%u,%p\n", callParams.threadId, callParams.time, frameIndex,
      +
      15417  createInfo.memoryTypeIndex,
      +
      15418  createInfo.flags,
      +
      15419  createInfo.blockSize,
      +
      15420  (uint64_t)createInfo.minBlockCount,
      +
      15421  (uint64_t)createInfo.maxBlockCount,
      +
      15422  createInfo.frameInUseCount,
      +
      15423  pool);
      +
      15424  Flush();
      +
      15425 }
      +
      15426 
      +
      15427 void VmaRecorder::RecordDestroyPool(uint32_t frameIndex, VmaPool pool)
      +
      15428 {
      +
      15429  CallParams callParams;
      +
      15430  GetBasicParams(callParams);
      15431 
      -
      15432 void VmaRecorder::RecordCreateImage(uint32_t frameIndex,
      -
      15433  const VkImageCreateInfo& imageCreateInfo,
      -
      15434  const VmaAllocationCreateInfo& allocCreateInfo,
      -
      15435  VmaAllocation allocation)
      -
      15436 {
      -
      15437  CallParams callParams;
      -
      15438  GetBasicParams(callParams);
      -
      15439 
      -
      15440  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15441  UserDataString userDataStr(allocCreateInfo.flags, allocCreateInfo.pUserData);
      -
      15442  fprintf(m_File, "%u,%.3f,%u,vmaCreateImage,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
      -
      15443  imageCreateInfo.flags,
      -
      15444  imageCreateInfo.imageType,
      -
      15445  imageCreateInfo.format,
      -
      15446  imageCreateInfo.extent.width,
      -
      15447  imageCreateInfo.extent.height,
      -
      15448  imageCreateInfo.extent.depth,
      -
      15449  imageCreateInfo.mipLevels,
      -
      15450  imageCreateInfo.arrayLayers,
      -
      15451  imageCreateInfo.samples,
      -
      15452  imageCreateInfo.tiling,
      -
      15453  imageCreateInfo.usage,
      -
      15454  imageCreateInfo.sharingMode,
      -
      15455  imageCreateInfo.initialLayout,
      -
      15456  allocCreateInfo.flags,
      -
      15457  allocCreateInfo.usage,
      -
      15458  allocCreateInfo.requiredFlags,
      -
      15459  allocCreateInfo.preferredFlags,
      -
      15460  allocCreateInfo.memoryTypeBits,
      -
      15461  allocCreateInfo.pool,
      -
      15462  allocation,
      -
      15463  userDataStr.GetString());
      -
      15464  Flush();
      -
      15465 }
      -
      15466 
      -
      15467 void VmaRecorder::RecordDestroyBuffer(uint32_t frameIndex,
      -
      15468  VmaAllocation allocation)
      -
      15469 {
      -
      15470  CallParams callParams;
      -
      15471  GetBasicParams(callParams);
      -
      15472 
      -
      15473  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15474  fprintf(m_File, "%u,%.3f,%u,vmaDestroyBuffer,%p\n", callParams.threadId, callParams.time, frameIndex,
      -
      15475  allocation);
      -
      15476  Flush();
      -
      15477 }
      -
      15478 
      -
      15479 void VmaRecorder::RecordDestroyImage(uint32_t frameIndex,
      -
      15480  VmaAllocation allocation)
      -
      15481 {
      -
      15482  CallParams callParams;
      -
      15483  GetBasicParams(callParams);
      -
      15484 
      -
      15485  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15486  fprintf(m_File, "%u,%.3f,%u,vmaDestroyImage,%p\n", callParams.threadId, callParams.time, frameIndex,
      -
      15487  allocation);
      -
      15488  Flush();
      -
      15489 }
      -
      15490 
      -
      15491 void VmaRecorder::RecordTouchAllocation(uint32_t frameIndex,
      -
      15492  VmaAllocation allocation)
      -
      15493 {
      -
      15494  CallParams callParams;
      -
      15495  GetBasicParams(callParams);
      -
      15496 
      -
      15497  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15498  fprintf(m_File, "%u,%.3f,%u,vmaTouchAllocation,%p\n", callParams.threadId, callParams.time, frameIndex,
      -
      15499  allocation);
      -
      15500  Flush();
      -
      15501 }
      -
      15502 
      -
      15503 void VmaRecorder::RecordGetAllocationInfo(uint32_t frameIndex,
      -
      15504  VmaAllocation allocation)
      -
      15505 {
      -
      15506  CallParams callParams;
      -
      15507  GetBasicParams(callParams);
      -
      15508 
      -
      15509  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15510  fprintf(m_File, "%u,%.3f,%u,vmaGetAllocationInfo,%p\n", callParams.threadId, callParams.time, frameIndex,
      -
      15511  allocation);
      -
      15512  Flush();
      -
      15513 }
      -
      15514 
      -
      15515 void VmaRecorder::RecordMakePoolAllocationsLost(uint32_t frameIndex,
      -
      15516  VmaPool pool)
      -
      15517 {
      -
      15518  CallParams callParams;
      -
      15519  GetBasicParams(callParams);
      -
      15520 
      -
      15521  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15522  fprintf(m_File, "%u,%.3f,%u,vmaMakePoolAllocationsLost,%p\n", callParams.threadId, callParams.time, frameIndex,
      -
      15523  pool);
      -
      15524  Flush();
      -
      15525 }
      -
      15526 
      -
      15527 void VmaRecorder::RecordDefragmentationBegin(uint32_t frameIndex,
      -
      15528  const VmaDefragmentationInfo2& info,
      - -
      15530 {
      -
      15531  CallParams callParams;
      -
      15532  GetBasicParams(callParams);
      -
      15533 
      -
      15534  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15535  fprintf(m_File, "%u,%.3f,%u,vmaDefragmentationBegin,%u,", callParams.threadId, callParams.time, frameIndex,
      -
      15536  info.flags);
      -
      15537  PrintPointerList(info.allocationCount, info.pAllocations);
      -
      15538  fprintf(m_File, ",");
      -
      15539  PrintPointerList(info.poolCount, info.pPools);
      -
      15540  fprintf(m_File, ",%llu,%u,%llu,%u,%p,%p\n",
      -
      15541  info.maxCpuBytesToMove,
      - -
      15543  info.maxGpuBytesToMove,
      - -
      15545  info.commandBuffer,
      -
      15546  ctx);
      -
      15547  Flush();
      -
      15548 }
      -
      15549 
      -
      15550 void VmaRecorder::RecordDefragmentationEnd(uint32_t frameIndex,
      - -
      15552 {
      -
      15553  CallParams callParams;
      -
      15554  GetBasicParams(callParams);
      -
      15555 
      -
      15556  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15557  fprintf(m_File, "%u,%.3f,%u,vmaDefragmentationEnd,%p\n", callParams.threadId, callParams.time, frameIndex,
      -
      15558  ctx);
      -
      15559  Flush();
      -
      15560 }
      -
      15561 
      -
      15562 void VmaRecorder::RecordSetPoolName(uint32_t frameIndex,
      -
      15563  VmaPool pool,
      -
      15564  const char* name)
      -
      15565 {
      -
      15566  CallParams callParams;
      -
      15567  GetBasicParams(callParams);
      -
      15568 
      -
      15569  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      -
      15570  fprintf(m_File, "%u,%.3f,%u,vmaSetPoolName,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
      -
      15571  pool, name != VMA_NULL ? name : "");
      -
      15572  Flush();
      -
      15573 }
      -
      15574 
      -
      15575 VmaRecorder::UserDataString::UserDataString(VmaAllocationCreateFlags allocFlags, const void* pUserData)
      +
      15432  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15433  fprintf(m_File, "%u,%.3f,%u,vmaDestroyPool,%p\n", callParams.threadId, callParams.time, frameIndex,
      +
      15434  pool);
      +
      15435  Flush();
      +
      15436 }
      +
      15437 
      +
      15438 void VmaRecorder::RecordAllocateMemory(uint32_t frameIndex,
      +
      15439  const VkMemoryRequirements& vkMemReq,
      +
      15440  const VmaAllocationCreateInfo& createInfo,
      +
      15441  VmaAllocation allocation)
      +
      15442 {
      +
      15443  CallParams callParams;
      +
      15444  GetBasicParams(callParams);
      +
      15445 
      +
      15446  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15447  UserDataString userDataStr(createInfo.flags, createInfo.pUserData);
      +
      15448  fprintf(m_File, "%u,%.3f,%u,vmaAllocateMemory,%llu,%llu,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
      +
      15449  vkMemReq.size,
      +
      15450  vkMemReq.alignment,
      +
      15451  vkMemReq.memoryTypeBits,
      +
      15452  createInfo.flags,
      +
      15453  createInfo.usage,
      +
      15454  createInfo.requiredFlags,
      +
      15455  createInfo.preferredFlags,
      +
      15456  createInfo.memoryTypeBits,
      +
      15457  createInfo.pool,
      +
      15458  allocation,
      +
      15459  userDataStr.GetString());
      +
      15460  Flush();
      +
      15461 }
      +
      15462 
      +
      15463 void VmaRecorder::RecordAllocateMemoryPages(uint32_t frameIndex,
      +
      15464  const VkMemoryRequirements& vkMemReq,
      +
      15465  const VmaAllocationCreateInfo& createInfo,
      +
      15466  uint64_t allocationCount,
      +
      15467  const VmaAllocation* pAllocations)
      +
      15468 {
      +
      15469  CallParams callParams;
      +
      15470  GetBasicParams(callParams);
      +
      15471 
      +
      15472  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15473  UserDataString userDataStr(createInfo.flags, createInfo.pUserData);
      +
      15474  fprintf(m_File, "%u,%.3f,%u,vmaAllocateMemoryPages,%llu,%llu,%u,%u,%u,%u,%u,%u,%p,", callParams.threadId, callParams.time, frameIndex,
      +
      15475  vkMemReq.size,
      +
      15476  vkMemReq.alignment,
      +
      15477  vkMemReq.memoryTypeBits,
      +
      15478  createInfo.flags,
      +
      15479  createInfo.usage,
      +
      15480  createInfo.requiredFlags,
      +
      15481  createInfo.preferredFlags,
      +
      15482  createInfo.memoryTypeBits,
      +
      15483  createInfo.pool);
      +
      15484  PrintPointerList(allocationCount, pAllocations);
      +
      15485  fprintf(m_File, ",%s\n", userDataStr.GetString());
      +
      15486  Flush();
      +
      15487 }
      +
      15488 
      +
      15489 void VmaRecorder::RecordAllocateMemoryForBuffer(uint32_t frameIndex,
      +
      15490  const VkMemoryRequirements& vkMemReq,
      +
      15491  bool requiresDedicatedAllocation,
      +
      15492  bool prefersDedicatedAllocation,
      +
      15493  const VmaAllocationCreateInfo& createInfo,
      +
      15494  VmaAllocation allocation)
      +
      15495 {
      +
      15496  CallParams callParams;
      +
      15497  GetBasicParams(callParams);
      +
      15498 
      +
      15499  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15500  UserDataString userDataStr(createInfo.flags, createInfo.pUserData);
      +
      15501  fprintf(m_File, "%u,%.3f,%u,vmaAllocateMemoryForBuffer,%llu,%llu,%u,%u,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
      +
      15502  vkMemReq.size,
      +
      15503  vkMemReq.alignment,
      +
      15504  vkMemReq.memoryTypeBits,
      +
      15505  requiresDedicatedAllocation ? 1 : 0,
      +
      15506  prefersDedicatedAllocation ? 1 : 0,
      +
      15507  createInfo.flags,
      +
      15508  createInfo.usage,
      +
      15509  createInfo.requiredFlags,
      +
      15510  createInfo.preferredFlags,
      +
      15511  createInfo.memoryTypeBits,
      +
      15512  createInfo.pool,
      +
      15513  allocation,
      +
      15514  userDataStr.GetString());
      +
      15515  Flush();
      +
      15516 }
      +
      15517 
      +
      15518 void VmaRecorder::RecordAllocateMemoryForImage(uint32_t frameIndex,
      +
      15519  const VkMemoryRequirements& vkMemReq,
      +
      15520  bool requiresDedicatedAllocation,
      +
      15521  bool prefersDedicatedAllocation,
      +
      15522  const VmaAllocationCreateInfo& createInfo,
      +
      15523  VmaAllocation allocation)
      +
      15524 {
      +
      15525  CallParams callParams;
      +
      15526  GetBasicParams(callParams);
      +
      15527 
      +
      15528  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15529  UserDataString userDataStr(createInfo.flags, createInfo.pUserData);
      +
      15530  fprintf(m_File, "%u,%.3f,%u,vmaAllocateMemoryForImage,%llu,%llu,%u,%u,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
      +
      15531  vkMemReq.size,
      +
      15532  vkMemReq.alignment,
      +
      15533  vkMemReq.memoryTypeBits,
      +
      15534  requiresDedicatedAllocation ? 1 : 0,
      +
      15535  prefersDedicatedAllocation ? 1 : 0,
      +
      15536  createInfo.flags,
      +
      15537  createInfo.usage,
      +
      15538  createInfo.requiredFlags,
      +
      15539  createInfo.preferredFlags,
      +
      15540  createInfo.memoryTypeBits,
      +
      15541  createInfo.pool,
      +
      15542  allocation,
      +
      15543  userDataStr.GetString());
      +
      15544  Flush();
      +
      15545 }
      +
      15546 
      +
      15547 void VmaRecorder::RecordFreeMemory(uint32_t frameIndex,
      +
      15548  VmaAllocation allocation)
      +
      15549 {
      +
      15550  CallParams callParams;
      +
      15551  GetBasicParams(callParams);
      +
      15552 
      +
      15553  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15554  fprintf(m_File, "%u,%.3f,%u,vmaFreeMemory,%p\n", callParams.threadId, callParams.time, frameIndex,
      +
      15555  allocation);
      +
      15556  Flush();
      +
      15557 }
      +
      15558 
      +
      15559 void VmaRecorder::RecordFreeMemoryPages(uint32_t frameIndex,
      +
      15560  uint64_t allocationCount,
      +
      15561  const VmaAllocation* pAllocations)
      +
      15562 {
      +
      15563  CallParams callParams;
      +
      15564  GetBasicParams(callParams);
      +
      15565 
      +
      15566  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15567  fprintf(m_File, "%u,%.3f,%u,vmaFreeMemoryPages,", callParams.threadId, callParams.time, frameIndex);
      +
      15568  PrintPointerList(allocationCount, pAllocations);
      +
      15569  fprintf(m_File, "\n");
      +
      15570  Flush();
      +
      15571 }
      +
      15572 
      +
      15573 void VmaRecorder::RecordSetAllocationUserData(uint32_t frameIndex,
      +
      15574  VmaAllocation allocation,
      +
      15575  const void* pUserData)
      15576 {
      -
      15577  if(pUserData != VMA_NULL)
      -
      15578  {
      -
      15579  if((allocFlags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0)
      -
      15580  {
      -
      15581  m_Str = (const char*)pUserData;
      -
      15582  }
      -
      15583  else
      -
      15584  {
      -
      15585  // If VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT is not specified, convert the string's memory address to a string and store it.
      -
      15586  snprintf(m_PtrStr, 17, "%p", pUserData);
      -
      15587  m_Str = m_PtrStr;
      -
      15588  }
      -
      15589  }
      -
      15590  else
      -
      15591  {
      -
      15592  m_Str = "";
      -
      15593  }
      -
      15594 }
      +
      15577  CallParams callParams;
      +
      15578  GetBasicParams(callParams);
      +
      15579 
      +
      15580  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15581  UserDataString userDataStr(
      +
      15582  allocation->IsUserDataString() ? VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT : 0,
      +
      15583  pUserData);
      +
      15584  fprintf(m_File, "%u,%.3f,%u,vmaSetAllocationUserData,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
      +
      15585  allocation,
      +
      15586  userDataStr.GetString());
      +
      15587  Flush();
      +
      15588 }
      +
      15589 
      +
      15590 void VmaRecorder::RecordCreateLostAllocation(uint32_t frameIndex,
      +
      15591  VmaAllocation allocation)
      +
      15592 {
      +
      15593  CallParams callParams;
      +
      15594  GetBasicParams(callParams);
      15595 
      -
      15596 void VmaRecorder::WriteConfiguration(
      -
      15597  const VkPhysicalDeviceProperties& devProps,
      -
      15598  const VkPhysicalDeviceMemoryProperties& memProps,
      -
      15599  uint32_t vulkanApiVersion,
      -
      15600  bool dedicatedAllocationExtensionEnabled,
      -
      15601  bool bindMemory2ExtensionEnabled,
      -
      15602  bool memoryBudgetExtensionEnabled,
      -
      15603  bool deviceCoherentMemoryExtensionEnabled)
      +
      15596  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15597  fprintf(m_File, "%u,%.3f,%u,vmaCreateLostAllocation,%p\n", callParams.threadId, callParams.time, frameIndex,
      +
      15598  allocation);
      +
      15599  Flush();
      +
      15600 }
      +
      15601 
      +
      15602 void VmaRecorder::RecordMapMemory(uint32_t frameIndex,
      +
      15603  VmaAllocation allocation)
      15604 {
      -
      15605  fprintf(m_File, "Config,Begin\n");
      -
      15606 
      -
      15607  fprintf(m_File, "VulkanApiVersion,%u,%u\n", VK_VERSION_MAJOR(vulkanApiVersion), VK_VERSION_MINOR(vulkanApiVersion));
      -
      15608 
      -
      15609  fprintf(m_File, "PhysicalDevice,apiVersion,%u\n", devProps.apiVersion);
      -
      15610  fprintf(m_File, "PhysicalDevice,driverVersion,%u\n", devProps.driverVersion);
      -
      15611  fprintf(m_File, "PhysicalDevice,vendorID,%u\n", devProps.vendorID);
      -
      15612  fprintf(m_File, "PhysicalDevice,deviceID,%u\n", devProps.deviceID);
      -
      15613  fprintf(m_File, "PhysicalDevice,deviceType,%u\n", devProps.deviceType);
      -
      15614  fprintf(m_File, "PhysicalDevice,deviceName,%s\n", devProps.deviceName);
      -
      15615 
      -
      15616  fprintf(m_File, "PhysicalDeviceLimits,maxMemoryAllocationCount,%u\n", devProps.limits.maxMemoryAllocationCount);
      -
      15617  fprintf(m_File, "PhysicalDeviceLimits,bufferImageGranularity,%llu\n", devProps.limits.bufferImageGranularity);
      -
      15618  fprintf(m_File, "PhysicalDeviceLimits,nonCoherentAtomSize,%llu\n", devProps.limits.nonCoherentAtomSize);
      +
      15605  CallParams callParams;
      +
      15606  GetBasicParams(callParams);
      +
      15607 
      +
      15608  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15609  fprintf(m_File, "%u,%.3f,%u,vmaMapMemory,%p\n", callParams.threadId, callParams.time, frameIndex,
      +
      15610  allocation);
      +
      15611  Flush();
      +
      15612 }
      +
      15613 
      +
      15614 void VmaRecorder::RecordUnmapMemory(uint32_t frameIndex,
      +
      15615  VmaAllocation allocation)
      +
      15616 {
      +
      15617  CallParams callParams;
      +
      15618  GetBasicParams(callParams);
      15619 
      -
      15620  fprintf(m_File, "PhysicalDeviceMemory,HeapCount,%u\n", memProps.memoryHeapCount);
      -
      15621  for(uint32_t i = 0; i < memProps.memoryHeapCount; ++i)
      -
      15622  {
      -
      15623  fprintf(m_File, "PhysicalDeviceMemory,Heap,%u,size,%llu\n", i, memProps.memoryHeaps[i].size);
      -
      15624  fprintf(m_File, "PhysicalDeviceMemory,Heap,%u,flags,%u\n", i, memProps.memoryHeaps[i].flags);
      -
      15625  }
      -
      15626  fprintf(m_File, "PhysicalDeviceMemory,TypeCount,%u\n", memProps.memoryTypeCount);
      -
      15627  for(uint32_t i = 0; i < memProps.memoryTypeCount; ++i)
      -
      15628  {
      -
      15629  fprintf(m_File, "PhysicalDeviceMemory,Type,%u,heapIndex,%u\n", i, memProps.memoryTypes[i].heapIndex);
      -
      15630  fprintf(m_File, "PhysicalDeviceMemory,Type,%u,propertyFlags,%u\n", i, memProps.memoryTypes[i].propertyFlags);
      -
      15631  }
      -
      15632 
      -
      15633  fprintf(m_File, "Extension,VK_KHR_dedicated_allocation,%u\n", dedicatedAllocationExtensionEnabled ? 1 : 0);
      -
      15634  fprintf(m_File, "Extension,VK_KHR_bind_memory2,%u\n", bindMemory2ExtensionEnabled ? 1 : 0);
      -
      15635  fprintf(m_File, "Extension,VK_EXT_memory_budget,%u\n", memoryBudgetExtensionEnabled ? 1 : 0);
      -
      15636  fprintf(m_File, "Extension,VK_AMD_device_coherent_memory,%u\n", deviceCoherentMemoryExtensionEnabled ? 1 : 0);
      -
      15637 
      -
      15638  fprintf(m_File, "Macro,VMA_DEBUG_ALWAYS_DEDICATED_MEMORY,%u\n", VMA_DEBUG_ALWAYS_DEDICATED_MEMORY ? 1 : 0);
      -
      15639  fprintf(m_File, "Macro,VMA_DEBUG_ALIGNMENT,%llu\n", (VkDeviceSize)VMA_DEBUG_ALIGNMENT);
      -
      15640  fprintf(m_File, "Macro,VMA_DEBUG_MARGIN,%llu\n", (VkDeviceSize)VMA_DEBUG_MARGIN);
      -
      15641  fprintf(m_File, "Macro,VMA_DEBUG_INITIALIZE_ALLOCATIONS,%u\n", VMA_DEBUG_INITIALIZE_ALLOCATIONS ? 1 : 0);
      -
      15642  fprintf(m_File, "Macro,VMA_DEBUG_DETECT_CORRUPTION,%u\n", VMA_DEBUG_DETECT_CORRUPTION ? 1 : 0);
      -
      15643  fprintf(m_File, "Macro,VMA_DEBUG_GLOBAL_MUTEX,%u\n", VMA_DEBUG_GLOBAL_MUTEX ? 1 : 0);
      -
      15644  fprintf(m_File, "Macro,VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY,%llu\n", (VkDeviceSize)VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY);
      -
      15645  fprintf(m_File, "Macro,VMA_SMALL_HEAP_MAX_SIZE,%llu\n", (VkDeviceSize)VMA_SMALL_HEAP_MAX_SIZE);
      -
      15646  fprintf(m_File, "Macro,VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE,%llu\n", (VkDeviceSize)VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE);
      -
      15647 
      -
      15648  fprintf(m_File, "Config,End\n");
      -
      15649 }
      -
      15650 
      -
      15651 void VmaRecorder::GetBasicParams(CallParams& outParams)
      -
      15652 {
      -
      15653  #if defined(_WIN32)
      -
      15654  outParams.threadId = GetCurrentThreadId();
      -
      15655  #else
      -
      15656  // Use C++11 features to get thread id and convert it to uint32_t.
      -
      15657  // There is room for optimization since sstream is quite slow.
      -
      15658  // Is there a better way to convert std::this_thread::get_id() to uint32_t?
      -
      15659  std::thread::id thread_id = std::this_thread::get_id();
      -
      15660  std::stringstream thread_id_to_string_converter;
      -
      15661  thread_id_to_string_converter << thread_id;
      -
      15662  std::string thread_id_as_string = thread_id_to_string_converter.str();
      -
      15663  outParams.threadId = static_cast<uint32_t>(std::stoi(thread_id_as_string.c_str()));
      -
      15664  #endif
      -
      15665 
      -
      15666  auto current_time = std::chrono::high_resolution_clock::now();
      -
      15667 
      -
      15668  outParams.time = std::chrono::duration<double, std::chrono::seconds::period>(current_time - m_RecordingStartTime).count();
      -
      15669 }
      -
      15670 
      -
      15671 void VmaRecorder::PrintPointerList(uint64_t count, const VmaAllocation* pItems)
      -
      15672 {
      -
      15673  if(count)
      -
      15674  {
      -
      15675  fprintf(m_File, "%p", pItems[0]);
      -
      15676  for(uint64_t i = 1; i < count; ++i)
      -
      15677  {
      -
      15678  fprintf(m_File, " %p", pItems[i]);
      -
      15679  }
      -
      15680  }
      -
      15681 }
      -
      15682 
      -
      15683 void VmaRecorder::Flush()
      +
      15620  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15621  fprintf(m_File, "%u,%.3f,%u,vmaUnmapMemory,%p\n", callParams.threadId, callParams.time, frameIndex,
      +
      15622  allocation);
      +
      15623  Flush();
      +
      15624 }
      +
      15625 
      +
      15626 void VmaRecorder::RecordFlushAllocation(uint32_t frameIndex,
      +
      15627  VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size)
      +
      15628 {
      +
      15629  CallParams callParams;
      +
      15630  GetBasicParams(callParams);
      +
      15631 
      +
      15632  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15633  fprintf(m_File, "%u,%.3f,%u,vmaFlushAllocation,%p,%llu,%llu\n", callParams.threadId, callParams.time, frameIndex,
      +
      15634  allocation,
      +
      15635  offset,
      +
      15636  size);
      +
      15637  Flush();
      +
      15638 }
      +
      15639 
      +
      15640 void VmaRecorder::RecordInvalidateAllocation(uint32_t frameIndex,
      +
      15641  VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size)
      +
      15642 {
      +
      15643  CallParams callParams;
      +
      15644  GetBasicParams(callParams);
      +
      15645 
      +
      15646  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15647  fprintf(m_File, "%u,%.3f,%u,vmaInvalidateAllocation,%p,%llu,%llu\n", callParams.threadId, callParams.time, frameIndex,
      +
      15648  allocation,
      +
      15649  offset,
      +
      15650  size);
      +
      15651  Flush();
      +
      15652 }
      +
      15653 
      +
      15654 void VmaRecorder::RecordCreateBuffer(uint32_t frameIndex,
      +
      15655  const VkBufferCreateInfo& bufCreateInfo,
      +
      15656  const VmaAllocationCreateInfo& allocCreateInfo,
      +
      15657  VmaAllocation allocation)
      +
      15658 {
      +
      15659  CallParams callParams;
      +
      15660  GetBasicParams(callParams);
      +
      15661 
      +
      15662  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15663  UserDataString userDataStr(allocCreateInfo.flags, allocCreateInfo.pUserData);
      +
      15664  fprintf(m_File, "%u,%.3f,%u,vmaCreateBuffer,%u,%llu,%u,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
      +
      15665  bufCreateInfo.flags,
      +
      15666  bufCreateInfo.size,
      +
      15667  bufCreateInfo.usage,
      +
      15668  bufCreateInfo.sharingMode,
      +
      15669  allocCreateInfo.flags,
      +
      15670  allocCreateInfo.usage,
      +
      15671  allocCreateInfo.requiredFlags,
      +
      15672  allocCreateInfo.preferredFlags,
      +
      15673  allocCreateInfo.memoryTypeBits,
      +
      15674  allocCreateInfo.pool,
      +
      15675  allocation,
      +
      15676  userDataStr.GetString());
      +
      15677  Flush();
      +
      15678 }
      +
      15679 
      +
      15680 void VmaRecorder::RecordCreateImage(uint32_t frameIndex,
      +
      15681  const VkImageCreateInfo& imageCreateInfo,
      +
      15682  const VmaAllocationCreateInfo& allocCreateInfo,
      +
      15683  VmaAllocation allocation)
      15684 {
      -
      15685  if((m_Flags & VMA_RECORD_FLUSH_AFTER_CALL_BIT) != 0)
      -
      15686  {
      -
      15687  fflush(m_File);
      -
      15688  }
      -
      15689 }
      -
      15690 
      -
      15691 #endif // #if VMA_RECORDING_ENABLED
      -
      15692 
      -
      15694 // VmaAllocationObjectAllocator
      -
      15695 
      -
      15696 VmaAllocationObjectAllocator::VmaAllocationObjectAllocator(const VkAllocationCallbacks* pAllocationCallbacks) :
      -
      15697  m_Allocator(pAllocationCallbacks, 1024)
      -
      15698 {
      -
      15699 }
      -
      15700 
      -
      15701 template<typename... Types> VmaAllocation VmaAllocationObjectAllocator::Allocate(Types... args)
      -
      15702 {
      -
      15703  VmaMutexLock mutexLock(m_Mutex);
      -
      15704  return m_Allocator.Alloc<Types...>(std::forward<Types>(args)...);
      -
      15705 }
      -
      15706 
      -
      15707 void VmaAllocationObjectAllocator::Free(VmaAllocation hAlloc)
      -
      15708 {
      -
      15709  VmaMutexLock mutexLock(m_Mutex);
      -
      15710  m_Allocator.Free(hAlloc);
      -
      15711 }
      -
      15712 
      -
      15714 // VmaAllocator_T
      -
      15715 
      -
      15716 VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) :
      -
      15717  m_UseMutex((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT) == 0),
      -
      15718  m_VulkanApiVersion(pCreateInfo->vulkanApiVersion != 0 ? pCreateInfo->vulkanApiVersion : VK_API_VERSION_1_0),
      -
      15719  m_UseKhrDedicatedAllocation((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0),
      -
      15720  m_UseKhrBindMemory2((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0),
      -
      15721  m_UseExtMemoryBudget((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0),
      -
      15722  m_UseAmdDeviceCoherentMemory((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT) != 0),
      -
      15723  m_UseKhrBufferDeviceAddress((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT) != 0),
      -
      15724  m_UseExtMemoryPriority((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT) != 0),
      -
      15725  m_hDevice(pCreateInfo->device),
      -
      15726  m_hInstance(pCreateInfo->instance),
      -
      15727  m_AllocationCallbacksSpecified(pCreateInfo->pAllocationCallbacks != VMA_NULL),
      -
      15728  m_AllocationCallbacks(pCreateInfo->pAllocationCallbacks ?
      -
      15729  *pCreateInfo->pAllocationCallbacks : VmaEmptyAllocationCallbacks),
      -
      15730  m_AllocationObjectAllocator(&m_AllocationCallbacks),
      -
      15731  m_HeapSizeLimitMask(0),
      -
      15732  m_PreferredLargeHeapBlockSize(0),
      -
      15733  m_PhysicalDevice(pCreateInfo->physicalDevice),
      -
      15734  m_CurrentFrameIndex(0),
      -
      15735  m_GpuDefragmentationMemoryTypeBits(UINT32_MAX),
      -
      15736  m_Pools(VmaStlAllocator<VmaPool>(GetAllocationCallbacks())),
      -
      15737  m_NextPoolId(0),
      -
      15738  m_GlobalMemoryTypeBits(UINT32_MAX)
      - -
      15740  ,m_pRecorder(VMA_NULL)
      -
      15741 #endif
      -
      15742 {
      -
      15743  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
      -
      15744  {
      -
      15745  m_UseKhrDedicatedAllocation = false;
      -
      15746  m_UseKhrBindMemory2 = false;
      -
      15747  }
      -
      15748 
      -
      15749  if(VMA_DEBUG_DETECT_CORRUPTION)
      -
      15750  {
      -
      15751  // Needs to be multiply of uint32_t size because we are going to write VMA_CORRUPTION_DETECTION_MAGIC_VALUE to it.
      -
      15752  VMA_ASSERT(VMA_DEBUG_MARGIN % sizeof(uint32_t) == 0);
      -
      15753  }
      -
      15754 
      -
      15755  VMA_ASSERT(pCreateInfo->physicalDevice && pCreateInfo->device && pCreateInfo->instance);
      +
      15685  CallParams callParams;
      +
      15686  GetBasicParams(callParams);
      +
      15687 
      +
      15688  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15689  UserDataString userDataStr(allocCreateInfo.flags, allocCreateInfo.pUserData);
      +
      15690  fprintf(m_File, "%u,%.3f,%u,vmaCreateImage,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%p,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
      +
      15691  imageCreateInfo.flags,
      +
      15692  imageCreateInfo.imageType,
      +
      15693  imageCreateInfo.format,
      +
      15694  imageCreateInfo.extent.width,
      +
      15695  imageCreateInfo.extent.height,
      +
      15696  imageCreateInfo.extent.depth,
      +
      15697  imageCreateInfo.mipLevels,
      +
      15698  imageCreateInfo.arrayLayers,
      +
      15699  imageCreateInfo.samples,
      +
      15700  imageCreateInfo.tiling,
      +
      15701  imageCreateInfo.usage,
      +
      15702  imageCreateInfo.sharingMode,
      +
      15703  imageCreateInfo.initialLayout,
      +
      15704  allocCreateInfo.flags,
      +
      15705  allocCreateInfo.usage,
      +
      15706  allocCreateInfo.requiredFlags,
      +
      15707  allocCreateInfo.preferredFlags,
      +
      15708  allocCreateInfo.memoryTypeBits,
      +
      15709  allocCreateInfo.pool,
      +
      15710  allocation,
      +
      15711  userDataStr.GetString());
      +
      15712  Flush();
      +
      15713 }
      +
      15714 
      +
      15715 void VmaRecorder::RecordDestroyBuffer(uint32_t frameIndex,
      +
      15716  VmaAllocation allocation)
      +
      15717 {
      +
      15718  CallParams callParams;
      +
      15719  GetBasicParams(callParams);
      +
      15720 
      +
      15721  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15722  fprintf(m_File, "%u,%.3f,%u,vmaDestroyBuffer,%p\n", callParams.threadId, callParams.time, frameIndex,
      +
      15723  allocation);
      +
      15724  Flush();
      +
      15725 }
      +
      15726 
      +
      15727 void VmaRecorder::RecordDestroyImage(uint32_t frameIndex,
      +
      15728  VmaAllocation allocation)
      +
      15729 {
      +
      15730  CallParams callParams;
      +
      15731  GetBasicParams(callParams);
      +
      15732 
      +
      15733  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15734  fprintf(m_File, "%u,%.3f,%u,vmaDestroyImage,%p\n", callParams.threadId, callParams.time, frameIndex,
      +
      15735  allocation);
      +
      15736  Flush();
      +
      15737 }
      +
      15738 
      +
      15739 void VmaRecorder::RecordTouchAllocation(uint32_t frameIndex,
      +
      15740  VmaAllocation allocation)
      +
      15741 {
      +
      15742  CallParams callParams;
      +
      15743  GetBasicParams(callParams);
      +
      15744 
      +
      15745  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15746  fprintf(m_File, "%u,%.3f,%u,vmaTouchAllocation,%p\n", callParams.threadId, callParams.time, frameIndex,
      +
      15747  allocation);
      +
      15748  Flush();
      +
      15749 }
      +
      15750 
      +
      15751 void VmaRecorder::RecordGetAllocationInfo(uint32_t frameIndex,
      +
      15752  VmaAllocation allocation)
      +
      15753 {
      +
      15754  CallParams callParams;
      +
      15755  GetBasicParams(callParams);
      15756 
      -
      15757  if(m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0))
      -
      15758  {
      -
      15759 #if !(VMA_DEDICATED_ALLOCATION)
      - -
      15761  {
      -
      15762  VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT set but required extensions are disabled by preprocessor macros.");
      -
      15763  }
      -
      15764 #endif
      -
      15765 #if !(VMA_BIND_MEMORY2)
      -
      15766  if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0)
      -
      15767  {
      -
      15768  VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT set but required extension is disabled by preprocessor macros.");
      -
      15769  }
      -
      15770 #endif
      -
      15771  }
      -
      15772 #if !(VMA_MEMORY_BUDGET)
      -
      15773  if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0)
      -
      15774  {
      -
      15775  VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT set but required extension is disabled by preprocessor macros.");
      -
      15776  }
      -
      15777 #endif
      -
      15778 #if !(VMA_BUFFER_DEVICE_ADDRESS)
      -
      15779  if(m_UseKhrBufferDeviceAddress)
      -
      15780  {
      -
      15781  VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT is set but required extension or Vulkan 1.2 is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro.");
      -
      15782  }
      -
      15783 #endif
      -
      15784 #if VMA_VULKAN_VERSION < 1002000
      -
      15785  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 2, 0))
      -
      15786  {
      -
      15787  VMA_ASSERT(0 && "vulkanApiVersion >= VK_API_VERSION_1_2 but required Vulkan version is disabled by preprocessor macros.");
      -
      15788  }
      -
      15789 #endif
      -
      15790 #if VMA_VULKAN_VERSION < 1001000
      -
      15791  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
      -
      15792  {
      -
      15793  VMA_ASSERT(0 && "vulkanApiVersion >= VK_API_VERSION_1_1 but required Vulkan version is disabled by preprocessor macros.");
      -
      15794  }
      -
      15795 #endif
      -
      15796 #if !(VMA_MEMORY_PRIORITY)
      -
      15797  if(m_UseExtMemoryPriority)
      -
      15798  {
      -
      15799  VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro.");
      -
      15800  }
      -
      15801 #endif
      -
      15802 
      -
      15803  memset(&m_DeviceMemoryCallbacks, 0 ,sizeof(m_DeviceMemoryCallbacks));
      -
      15804  memset(&m_PhysicalDeviceProperties, 0, sizeof(m_PhysicalDeviceProperties));
      -
      15805  memset(&m_MemProps, 0, sizeof(m_MemProps));
      -
      15806 
      -
      15807  memset(&m_pBlockVectors, 0, sizeof(m_pBlockVectors));
      -
      15808  memset(&m_pDedicatedAllocations, 0, sizeof(m_pDedicatedAllocations));
      -
      15809  memset(&m_VulkanFunctions, 0, sizeof(m_VulkanFunctions));
      -
      15810 
      -
      15811  if(pCreateInfo->pDeviceMemoryCallbacks != VMA_NULL)
      -
      15812  {
      -
      15813  m_DeviceMemoryCallbacks.pUserData = pCreateInfo->pDeviceMemoryCallbacks->pUserData;
      -
      15814  m_DeviceMemoryCallbacks.pfnAllocate = pCreateInfo->pDeviceMemoryCallbacks->pfnAllocate;
      -
      15815  m_DeviceMemoryCallbacks.pfnFree = pCreateInfo->pDeviceMemoryCallbacks->pfnFree;
      -
      15816  }
      -
      15817 
      -
      15818  ImportVulkanFunctions(pCreateInfo->pVulkanFunctions);
      -
      15819 
      -
      15820  (*m_VulkanFunctions.vkGetPhysicalDeviceProperties)(m_PhysicalDevice, &m_PhysicalDeviceProperties);
      -
      15821  (*m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties)(m_PhysicalDevice, &m_MemProps);
      +
      15757  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15758  fprintf(m_File, "%u,%.3f,%u,vmaGetAllocationInfo,%p\n", callParams.threadId, callParams.time, frameIndex,
      +
      15759  allocation);
      +
      15760  Flush();
      +
      15761 }
      +
      15762 
      +
      15763 void VmaRecorder::RecordMakePoolAllocationsLost(uint32_t frameIndex,
      +
      15764  VmaPool pool)
      +
      15765 {
      +
      15766  CallParams callParams;
      +
      15767  GetBasicParams(callParams);
      +
      15768 
      +
      15769  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15770  fprintf(m_File, "%u,%.3f,%u,vmaMakePoolAllocationsLost,%p\n", callParams.threadId, callParams.time, frameIndex,
      +
      15771  pool);
      +
      15772  Flush();
      +
      15773 }
      +
      15774 
      +
      15775 void VmaRecorder::RecordDefragmentationBegin(uint32_t frameIndex,
      +
      15776  const VmaDefragmentationInfo2& info,
      + +
      15778 {
      +
      15779  CallParams callParams;
      +
      15780  GetBasicParams(callParams);
      +
      15781 
      +
      15782  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15783  fprintf(m_File, "%u,%.3f,%u,vmaDefragmentationBegin,%u,", callParams.threadId, callParams.time, frameIndex,
      +
      15784  info.flags);
      +
      15785  PrintPointerList(info.allocationCount, info.pAllocations);
      +
      15786  fprintf(m_File, ",");
      +
      15787  PrintPointerList(info.poolCount, info.pPools);
      +
      15788  fprintf(m_File, ",%llu,%u,%llu,%u,%p,%p\n",
      +
      15789  info.maxCpuBytesToMove,
      + +
      15791  info.maxGpuBytesToMove,
      + +
      15793  info.commandBuffer,
      +
      15794  ctx);
      +
      15795  Flush();
      +
      15796 }
      +
      15797 
      +
      15798 void VmaRecorder::RecordDefragmentationEnd(uint32_t frameIndex,
      + +
      15800 {
      +
      15801  CallParams callParams;
      +
      15802  GetBasicParams(callParams);
      +
      15803 
      +
      15804  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15805  fprintf(m_File, "%u,%.3f,%u,vmaDefragmentationEnd,%p\n", callParams.threadId, callParams.time, frameIndex,
      +
      15806  ctx);
      +
      15807  Flush();
      +
      15808 }
      +
      15809 
      +
      15810 void VmaRecorder::RecordSetPoolName(uint32_t frameIndex,
      +
      15811  VmaPool pool,
      +
      15812  const char* name)
      +
      15813 {
      +
      15814  CallParams callParams;
      +
      15815  GetBasicParams(callParams);
      +
      15816 
      +
      15817  VmaMutexLock lock(m_FileMutex, m_UseMutex);
      +
      15818  fprintf(m_File, "%u,%.3f,%u,vmaSetPoolName,%p,%s\n", callParams.threadId, callParams.time, frameIndex,
      +
      15819  pool, name != VMA_NULL ? name : "");
      +
      15820  Flush();
      +
      15821 }
      15822 
      -
      15823  VMA_ASSERT(VmaIsPow2(VMA_DEBUG_ALIGNMENT));
      -
      15824  VMA_ASSERT(VmaIsPow2(VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY));
      -
      15825  VMA_ASSERT(VmaIsPow2(m_PhysicalDeviceProperties.limits.bufferImageGranularity));
      -
      15826  VMA_ASSERT(VmaIsPow2(m_PhysicalDeviceProperties.limits.nonCoherentAtomSize));
      -
      15827 
      -
      15828  m_PreferredLargeHeapBlockSize = (pCreateInfo->preferredLargeHeapBlockSize != 0) ?
      -
      15829  pCreateInfo->preferredLargeHeapBlockSize : static_cast<VkDeviceSize>(VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE);
      -
      15830 
      -
      15831  m_GlobalMemoryTypeBits = CalculateGlobalMemoryTypeBits();
      -
      15832 
      -
      15833  if(pCreateInfo->pHeapSizeLimit != VMA_NULL)
      -
      15834  {
      -
      15835  for(uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex)
      -
      15836  {
      -
      15837  const VkDeviceSize limit = pCreateInfo->pHeapSizeLimit[heapIndex];
      -
      15838  if(limit != VK_WHOLE_SIZE)
      -
      15839  {
      -
      15840  m_HeapSizeLimitMask |= 1u << heapIndex;
      -
      15841  if(limit < m_MemProps.memoryHeaps[heapIndex].size)
      -
      15842  {
      -
      15843  m_MemProps.memoryHeaps[heapIndex].size = limit;
      -
      15844  }
      -
      15845  }
      -
      15846  }
      -
      15847  }
      -
      15848 
      -
      15849  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
      -
      15850  {
      -
      15851  const VkDeviceSize preferredBlockSize = CalcPreferredBlockSize(memTypeIndex);
      -
      15852 
      -
      15853  m_pBlockVectors[memTypeIndex] = vma_new(this, VmaBlockVector)(
      -
      15854  this,
      -
      15855  VK_NULL_HANDLE, // hParentPool
      -
      15856  memTypeIndex,
      -
      15857  preferredBlockSize,
      -
      15858  0,
      -
      15859  SIZE_MAX,
      -
      15860  GetBufferImageGranularity(),
      -
      15861  pCreateInfo->frameInUseCount,
      -
      15862  false, // explicitBlockSize
      -
      15863  false, // linearAlgorithm
      -
      15864  0.5f); // priority (0.5 is the default per Vulkan spec)
      -
      15865  // No need to call m_pBlockVectors[memTypeIndex][blockVectorTypeIndex]->CreateMinBlocks here,
      -
      15866  // becase minBlockCount is 0.
      -
      15867  m_pDedicatedAllocations[memTypeIndex] = vma_new(this, AllocationVectorType)(VmaStlAllocator<VmaAllocation>(GetAllocationCallbacks()));
      -
      15868 
      -
      15869  }
      -
      15870 }
      -
      15871 
      -
      15872 VkResult VmaAllocator_T::Init(const VmaAllocatorCreateInfo* pCreateInfo)
      -
      15873 {
      -
      15874  VkResult res = VK_SUCCESS;
      -
      15875 
      -
      15876  if(pCreateInfo->pRecordSettings != VMA_NULL &&
      -
      15877  !VmaStrIsEmpty(pCreateInfo->pRecordSettings->pFilePath))
      -
      15878  {
      -
      15879 #if VMA_RECORDING_ENABLED
      -
      15880  m_pRecorder = vma_new(this, VmaRecorder)();
      -
      15881  res = m_pRecorder->Init(*pCreateInfo->pRecordSettings, m_UseMutex);
      -
      15882  if(res != VK_SUCCESS)
      -
      15883  {
      -
      15884  return res;
      -
      15885  }
      -
      15886  m_pRecorder->WriteConfiguration(
      -
      15887  m_PhysicalDeviceProperties,
      -
      15888  m_MemProps,
      -
      15889  m_VulkanApiVersion,
      -
      15890  m_UseKhrDedicatedAllocation,
      -
      15891  m_UseKhrBindMemory2,
      -
      15892  m_UseExtMemoryBudget,
      -
      15893  m_UseAmdDeviceCoherentMemory);
      -
      15894  m_pRecorder->RecordCreateAllocator(GetCurrentFrameIndex());
      -
      15895 #else
      -
      15896  VMA_ASSERT(0 && "VmaAllocatorCreateInfo::pRecordSettings used, but not supported due to VMA_RECORDING_ENABLED not defined to 1.");
      -
      15897  return VK_ERROR_FEATURE_NOT_PRESENT;
      -
      15898 #endif
      -
      15899  }
      -
      15900 
      -
      15901 #if VMA_MEMORY_BUDGET
      -
      15902  if(m_UseExtMemoryBudget)
      -
      15903  {
      -
      15904  UpdateVulkanBudget();
      -
      15905  }
      -
      15906 #endif // #if VMA_MEMORY_BUDGET
      -
      15907 
      -
      15908  return res;
      -
      15909 }
      -
      15910 
      -
      15911 VmaAllocator_T::~VmaAllocator_T()
      -
      15912 {
      -
      15913 #if VMA_RECORDING_ENABLED
      -
      15914  if(m_pRecorder != VMA_NULL)
      -
      15915  {
      -
      15916  m_pRecorder->RecordDestroyAllocator(GetCurrentFrameIndex());
      -
      15917  vma_delete(this, m_pRecorder);
      -
      15918  }
      -
      15919 #endif
      -
      15920 
      -
      15921  VMA_ASSERT(m_Pools.empty());
      -
      15922 
      -
      15923  for(size_t i = GetMemoryTypeCount(); i--; )
      -
      15924  {
      -
      15925  if(m_pDedicatedAllocations[i] != VMA_NULL && !m_pDedicatedAllocations[i]->empty())
      -
      15926  {
      -
      15927  VMA_ASSERT(0 && "Unfreed dedicated allocations found.");
      -
      15928  }
      -
      15929 
      -
      15930  vma_delete(this, m_pDedicatedAllocations[i]);
      -
      15931  vma_delete(this, m_pBlockVectors[i]);
      -
      15932  }
      -
      15933 }
      -
      15934 
      -
      15935 void VmaAllocator_T::ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunctions)
      -
      15936 {
      -
      15937 #if VMA_STATIC_VULKAN_FUNCTIONS == 1
      -
      15938  ImportVulkanFunctions_Static();
      -
      15939 #endif
      +
      15823 VmaRecorder::UserDataString::UserDataString(VmaAllocationCreateFlags allocFlags, const void* pUserData)
      +
      15824 {
      +
      15825  if(pUserData != VMA_NULL)
      +
      15826  {
      +
      15827  if((allocFlags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0)
      +
      15828  {
      +
      15829  m_Str = (const char*)pUserData;
      +
      15830  }
      +
      15831  else
      +
      15832  {
      +
      15833  // If VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT is not specified, convert the string's memory address to a string and store it.
      +
      15834  snprintf(m_PtrStr, 17, "%p", pUserData);
      +
      15835  m_Str = m_PtrStr;
      +
      15836  }
      +
      15837  }
      +
      15838  else
      +
      15839  {
      +
      15840  m_Str = "";
      +
      15841  }
      +
      15842 }
      +
      15843 
      +
      15844 void VmaRecorder::WriteConfiguration(
      +
      15845  const VkPhysicalDeviceProperties& devProps,
      +
      15846  const VkPhysicalDeviceMemoryProperties& memProps,
      +
      15847  uint32_t vulkanApiVersion,
      +
      15848  bool dedicatedAllocationExtensionEnabled,
      +
      15849  bool bindMemory2ExtensionEnabled,
      +
      15850  bool memoryBudgetExtensionEnabled,
      +
      15851  bool deviceCoherentMemoryExtensionEnabled)
      +
      15852 {
      +
      15853  fprintf(m_File, "Config,Begin\n");
      +
      15854 
      +
      15855  fprintf(m_File, "VulkanApiVersion,%u,%u\n", VK_VERSION_MAJOR(vulkanApiVersion), VK_VERSION_MINOR(vulkanApiVersion));
      +
      15856 
      +
      15857  fprintf(m_File, "PhysicalDevice,apiVersion,%u\n", devProps.apiVersion);
      +
      15858  fprintf(m_File, "PhysicalDevice,driverVersion,%u\n", devProps.driverVersion);
      +
      15859  fprintf(m_File, "PhysicalDevice,vendorID,%u\n", devProps.vendorID);
      +
      15860  fprintf(m_File, "PhysicalDevice,deviceID,%u\n", devProps.deviceID);
      +
      15861  fprintf(m_File, "PhysicalDevice,deviceType,%u\n", devProps.deviceType);
      +
      15862  fprintf(m_File, "PhysicalDevice,deviceName,%s\n", devProps.deviceName);
      +
      15863 
      +
      15864  fprintf(m_File, "PhysicalDeviceLimits,maxMemoryAllocationCount,%u\n", devProps.limits.maxMemoryAllocationCount);
      +
      15865  fprintf(m_File, "PhysicalDeviceLimits,bufferImageGranularity,%llu\n", devProps.limits.bufferImageGranularity);
      +
      15866  fprintf(m_File, "PhysicalDeviceLimits,nonCoherentAtomSize,%llu\n", devProps.limits.nonCoherentAtomSize);
      +
      15867 
      +
      15868  fprintf(m_File, "PhysicalDeviceMemory,HeapCount,%u\n", memProps.memoryHeapCount);
      +
      15869  for(uint32_t i = 0; i < memProps.memoryHeapCount; ++i)
      +
      15870  {
      +
      15871  fprintf(m_File, "PhysicalDeviceMemory,Heap,%u,size,%llu\n", i, memProps.memoryHeaps[i].size);
      +
      15872  fprintf(m_File, "PhysicalDeviceMemory,Heap,%u,flags,%u\n", i, memProps.memoryHeaps[i].flags);
      +
      15873  }
      +
      15874  fprintf(m_File, "PhysicalDeviceMemory,TypeCount,%u\n", memProps.memoryTypeCount);
      +
      15875  for(uint32_t i = 0; i < memProps.memoryTypeCount; ++i)
      +
      15876  {
      +
      15877  fprintf(m_File, "PhysicalDeviceMemory,Type,%u,heapIndex,%u\n", i, memProps.memoryTypes[i].heapIndex);
      +
      15878  fprintf(m_File, "PhysicalDeviceMemory,Type,%u,propertyFlags,%u\n", i, memProps.memoryTypes[i].propertyFlags);
      +
      15879  }
      +
      15880 
      +
      15881  fprintf(m_File, "Extension,VK_KHR_dedicated_allocation,%u\n", dedicatedAllocationExtensionEnabled ? 1 : 0);
      +
      15882  fprintf(m_File, "Extension,VK_KHR_bind_memory2,%u\n", bindMemory2ExtensionEnabled ? 1 : 0);
      +
      15883  fprintf(m_File, "Extension,VK_EXT_memory_budget,%u\n", memoryBudgetExtensionEnabled ? 1 : 0);
      +
      15884  fprintf(m_File, "Extension,VK_AMD_device_coherent_memory,%u\n", deviceCoherentMemoryExtensionEnabled ? 1 : 0);
      +
      15885 
      +
      15886  fprintf(m_File, "Macro,VMA_DEBUG_ALWAYS_DEDICATED_MEMORY,%u\n", VMA_DEBUG_ALWAYS_DEDICATED_MEMORY ? 1 : 0);
      +
      15887  fprintf(m_File, "Macro,VMA_DEBUG_ALIGNMENT,%llu\n", (VkDeviceSize)VMA_DEBUG_ALIGNMENT);
      +
      15888  fprintf(m_File, "Macro,VMA_DEBUG_MARGIN,%llu\n", (VkDeviceSize)VMA_DEBUG_MARGIN);
      +
      15889  fprintf(m_File, "Macro,VMA_DEBUG_INITIALIZE_ALLOCATIONS,%u\n", VMA_DEBUG_INITIALIZE_ALLOCATIONS ? 1 : 0);
      +
      15890  fprintf(m_File, "Macro,VMA_DEBUG_DETECT_CORRUPTION,%u\n", VMA_DEBUG_DETECT_CORRUPTION ? 1 : 0);
      +
      15891  fprintf(m_File, "Macro,VMA_DEBUG_GLOBAL_MUTEX,%u\n", VMA_DEBUG_GLOBAL_MUTEX ? 1 : 0);
      +
      15892  fprintf(m_File, "Macro,VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY,%llu\n", (VkDeviceSize)VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY);
      +
      15893  fprintf(m_File, "Macro,VMA_SMALL_HEAP_MAX_SIZE,%llu\n", (VkDeviceSize)VMA_SMALL_HEAP_MAX_SIZE);
      +
      15894  fprintf(m_File, "Macro,VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE,%llu\n", (VkDeviceSize)VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE);
      +
      15895 
      +
      15896  fprintf(m_File, "Config,End\n");
      +
      15897 }
      +
      15898 
      +
      15899 void VmaRecorder::GetBasicParams(CallParams& outParams)
      +
      15900 {
      +
      15901  #if defined(_WIN32)
      +
      15902  outParams.threadId = GetCurrentThreadId();
      +
      15903  #else
      +
      15904  // Use C++11 features to get thread id and convert it to uint32_t.
      +
      15905  // There is room for optimization since sstream is quite slow.
      +
      15906  // Is there a better way to convert std::this_thread::get_id() to uint32_t?
      +
      15907  std::thread::id thread_id = std::this_thread::get_id();
      +
      15908  std::stringstream thread_id_to_string_converter;
      +
      15909  thread_id_to_string_converter << thread_id;
      +
      15910  std::string thread_id_as_string = thread_id_to_string_converter.str();
      +
      15911  outParams.threadId = static_cast<uint32_t>(std::stoi(thread_id_as_string.c_str()));
      +
      15912  #endif
      +
      15913 
      +
      15914  auto current_time = std::chrono::high_resolution_clock::now();
      +
      15915 
      +
      15916  outParams.time = std::chrono::duration<double, std::chrono::seconds::period>(current_time - m_RecordingStartTime).count();
      +
      15917 }
      +
      15918 
      +
      15919 void VmaRecorder::PrintPointerList(uint64_t count, const VmaAllocation* pItems)
      +
      15920 {
      +
      15921  if(count)
      +
      15922  {
      +
      15923  fprintf(m_File, "%p", pItems[0]);
      +
      15924  for(uint64_t i = 1; i < count; ++i)
      +
      15925  {
      +
      15926  fprintf(m_File, " %p", pItems[i]);
      +
      15927  }
      +
      15928  }
      +
      15929 }
      +
      15930 
      +
      15931 void VmaRecorder::Flush()
      +
      15932 {
      +
      15933  if((m_Flags & VMA_RECORD_FLUSH_AFTER_CALL_BIT) != 0)
      +
      15934  {
      +
      15935  fflush(m_File);
      +
      15936  }
      +
      15937 }
      +
      15938 
      +
      15939 #endif // #if VMA_RECORDING_ENABLED
      15940 
      -
      15941  if(pVulkanFunctions != VMA_NULL)
      -
      15942  {
      -
      15943  ImportVulkanFunctions_Custom(pVulkanFunctions);
      -
      15944  }
      -
      15945 
      -
      15946 #if VMA_DYNAMIC_VULKAN_FUNCTIONS == 1
      -
      15947  ImportVulkanFunctions_Dynamic();
      -
      15948 #endif
      -
      15949 
      -
      15950  ValidateVulkanFunctions();
      -
      15951 }
      -
      15952 
      -
      15953 #if VMA_STATIC_VULKAN_FUNCTIONS == 1
      +
      15942 // VmaAllocationObjectAllocator
      +
      15943 
      +
      15944 VmaAllocationObjectAllocator::VmaAllocationObjectAllocator(const VkAllocationCallbacks* pAllocationCallbacks) :
      +
      15945  m_Allocator(pAllocationCallbacks, 1024)
      +
      15946 {
      +
      15947 }
      +
      15948 
      +
      15949 template<typename... Types> VmaAllocation VmaAllocationObjectAllocator::Allocate(Types... args)
      +
      15950 {
      +
      15951  VmaMutexLock mutexLock(m_Mutex);
      +
      15952  return m_Allocator.Alloc<Types...>(std::forward<Types>(args)...);
      +
      15953 }
      15954 
      -
      15955 void VmaAllocator_T::ImportVulkanFunctions_Static()
      +
      15955 void VmaAllocationObjectAllocator::Free(VmaAllocation hAlloc)
      15956 {
      -
      15957  // Vulkan 1.0
      -
      15958  m_VulkanFunctions.vkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties)vkGetPhysicalDeviceProperties;
      -
      15959  m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties)vkGetPhysicalDeviceMemoryProperties;
      -
      15960  m_VulkanFunctions.vkAllocateMemory = (PFN_vkAllocateMemory)vkAllocateMemory;
      -
      15961  m_VulkanFunctions.vkFreeMemory = (PFN_vkFreeMemory)vkFreeMemory;
      -
      15962  m_VulkanFunctions.vkMapMemory = (PFN_vkMapMemory)vkMapMemory;
      -
      15963  m_VulkanFunctions.vkUnmapMemory = (PFN_vkUnmapMemory)vkUnmapMemory;
      -
      15964  m_VulkanFunctions.vkFlushMappedMemoryRanges = (PFN_vkFlushMappedMemoryRanges)vkFlushMappedMemoryRanges;
      -
      15965  m_VulkanFunctions.vkInvalidateMappedMemoryRanges = (PFN_vkInvalidateMappedMemoryRanges)vkInvalidateMappedMemoryRanges;
      -
      15966  m_VulkanFunctions.vkBindBufferMemory = (PFN_vkBindBufferMemory)vkBindBufferMemory;
      -
      15967  m_VulkanFunctions.vkBindImageMemory = (PFN_vkBindImageMemory)vkBindImageMemory;
      -
      15968  m_VulkanFunctions.vkGetBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements)vkGetBufferMemoryRequirements;
      -
      15969  m_VulkanFunctions.vkGetImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)vkGetImageMemoryRequirements;
      -
      15970  m_VulkanFunctions.vkCreateBuffer = (PFN_vkCreateBuffer)vkCreateBuffer;
      -
      15971  m_VulkanFunctions.vkDestroyBuffer = (PFN_vkDestroyBuffer)vkDestroyBuffer;
      -
      15972  m_VulkanFunctions.vkCreateImage = (PFN_vkCreateImage)vkCreateImage;
      -
      15973  m_VulkanFunctions.vkDestroyImage = (PFN_vkDestroyImage)vkDestroyImage;
      -
      15974  m_VulkanFunctions.vkCmdCopyBuffer = (PFN_vkCmdCopyBuffer)vkCmdCopyBuffer;
      -
      15975 
      -
      15976  // Vulkan 1.1
      -
      15977 #if VMA_VULKAN_VERSION >= 1001000
      -
      15978  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
      -
      15979  {
      -
      15980  m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR = (PFN_vkGetBufferMemoryRequirements2)vkGetBufferMemoryRequirements2;
      -
      15981  m_VulkanFunctions.vkGetImageMemoryRequirements2KHR = (PFN_vkGetImageMemoryRequirements2)vkGetImageMemoryRequirements2;
      -
      15982  m_VulkanFunctions.vkBindBufferMemory2KHR = (PFN_vkBindBufferMemory2)vkBindBufferMemory2;
      -
      15983  m_VulkanFunctions.vkBindImageMemory2KHR = (PFN_vkBindImageMemory2)vkBindImageMemory2;
      -
      15984  m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR = (PFN_vkGetPhysicalDeviceMemoryProperties2)vkGetPhysicalDeviceMemoryProperties2;
      -
      15985  }
      -
      15986 #endif
      -
      15987 }
      -
      15988 
      -
      15989 #endif // #if VMA_STATIC_VULKAN_FUNCTIONS == 1
      -
      15990 
      -
      15991 void VmaAllocator_T::ImportVulkanFunctions_Custom(const VmaVulkanFunctions* pVulkanFunctions)
      -
      15992 {
      -
      15993  VMA_ASSERT(pVulkanFunctions != VMA_NULL);
      -
      15994 
      -
      15995 #define VMA_COPY_IF_NOT_NULL(funcName) \
      -
      15996  if(pVulkanFunctions->funcName != VMA_NULL) m_VulkanFunctions.funcName = pVulkanFunctions->funcName;
      -
      15997 
      -
      15998  VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceProperties);
      -
      15999  VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceMemoryProperties);
      -
      16000  VMA_COPY_IF_NOT_NULL(vkAllocateMemory);
      -
      16001  VMA_COPY_IF_NOT_NULL(vkFreeMemory);
      -
      16002  VMA_COPY_IF_NOT_NULL(vkMapMemory);
      -
      16003  VMA_COPY_IF_NOT_NULL(vkUnmapMemory);
      -
      16004  VMA_COPY_IF_NOT_NULL(vkFlushMappedMemoryRanges);
      -
      16005  VMA_COPY_IF_NOT_NULL(vkInvalidateMappedMemoryRanges);
      -
      16006  VMA_COPY_IF_NOT_NULL(vkBindBufferMemory);
      -
      16007  VMA_COPY_IF_NOT_NULL(vkBindImageMemory);
      -
      16008  VMA_COPY_IF_NOT_NULL(vkGetBufferMemoryRequirements);
      -
      16009  VMA_COPY_IF_NOT_NULL(vkGetImageMemoryRequirements);
      -
      16010  VMA_COPY_IF_NOT_NULL(vkCreateBuffer);
      -
      16011  VMA_COPY_IF_NOT_NULL(vkDestroyBuffer);
      -
      16012  VMA_COPY_IF_NOT_NULL(vkCreateImage);
      -
      16013  VMA_COPY_IF_NOT_NULL(vkDestroyImage);
      -
      16014  VMA_COPY_IF_NOT_NULL(vkCmdCopyBuffer);
      -
      16015 
      -
      16016 #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
      -
      16017  VMA_COPY_IF_NOT_NULL(vkGetBufferMemoryRequirements2KHR);
      -
      16018  VMA_COPY_IF_NOT_NULL(vkGetImageMemoryRequirements2KHR);
      -
      16019 #endif
      -
      16020 
      -
      16021 #if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000
      -
      16022  VMA_COPY_IF_NOT_NULL(vkBindBufferMemory2KHR);
      -
      16023  VMA_COPY_IF_NOT_NULL(vkBindImageMemory2KHR);
      -
      16024 #endif
      -
      16025 
      -
      16026 #if VMA_MEMORY_BUDGET
      -
      16027  VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceMemoryProperties2KHR);
      -
      16028 #endif
      -
      16029 
      -
      16030 #undef VMA_COPY_IF_NOT_NULL
      -
      16031 }
      -
      16032 
      -
      16033 #if VMA_DYNAMIC_VULKAN_FUNCTIONS == 1
      -
      16034 
      -
      16035 void VmaAllocator_T::ImportVulkanFunctions_Dynamic()
      -
      16036 {
      -
      16037 #define VMA_FETCH_INSTANCE_FUNC(memberName, functionPointerType, functionNameString) \
      -
      16038  if(m_VulkanFunctions.memberName == VMA_NULL) \
      -
      16039  m_VulkanFunctions.memberName = \
      -
      16040  (functionPointerType)vkGetInstanceProcAddr(m_hInstance, functionNameString);
      -
      16041 #define VMA_FETCH_DEVICE_FUNC(memberName, functionPointerType, functionNameString) \
      -
      16042  if(m_VulkanFunctions.memberName == VMA_NULL) \
      -
      16043  m_VulkanFunctions.memberName = \
      -
      16044  (functionPointerType)vkGetDeviceProcAddr(m_hDevice, functionNameString);
      -
      16045 
      -
      16046  VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceProperties, PFN_vkGetPhysicalDeviceProperties, "vkGetPhysicalDeviceProperties");
      -
      16047  VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties, PFN_vkGetPhysicalDeviceMemoryProperties, "vkGetPhysicalDeviceMemoryProperties");
      -
      16048  VMA_FETCH_DEVICE_FUNC(vkAllocateMemory, PFN_vkAllocateMemory, "vkAllocateMemory");
      -
      16049  VMA_FETCH_DEVICE_FUNC(vkFreeMemory, PFN_vkFreeMemory, "vkFreeMemory");
      -
      16050  VMA_FETCH_DEVICE_FUNC(vkMapMemory, PFN_vkMapMemory, "vkMapMemory");
      -
      16051  VMA_FETCH_DEVICE_FUNC(vkUnmapMemory, PFN_vkUnmapMemory, "vkUnmapMemory");
      -
      16052  VMA_FETCH_DEVICE_FUNC(vkFlushMappedMemoryRanges, PFN_vkFlushMappedMemoryRanges, "vkFlushMappedMemoryRanges");
      -
      16053  VMA_FETCH_DEVICE_FUNC(vkInvalidateMappedMemoryRanges, PFN_vkInvalidateMappedMemoryRanges, "vkInvalidateMappedMemoryRanges");
      -
      16054  VMA_FETCH_DEVICE_FUNC(vkBindBufferMemory, PFN_vkBindBufferMemory, "vkBindBufferMemory");
      -
      16055  VMA_FETCH_DEVICE_FUNC(vkBindImageMemory, PFN_vkBindImageMemory, "vkBindImageMemory");
      -
      16056  VMA_FETCH_DEVICE_FUNC(vkGetBufferMemoryRequirements, PFN_vkGetBufferMemoryRequirements, "vkGetBufferMemoryRequirements");
      -
      16057  VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements, PFN_vkGetImageMemoryRequirements, "vkGetImageMemoryRequirements");
      -
      16058  VMA_FETCH_DEVICE_FUNC(vkCreateBuffer, PFN_vkCreateBuffer, "vkCreateBuffer");
      -
      16059  VMA_FETCH_DEVICE_FUNC(vkDestroyBuffer, PFN_vkDestroyBuffer, "vkDestroyBuffer");
      -
      16060  VMA_FETCH_DEVICE_FUNC(vkCreateImage, PFN_vkCreateImage, "vkCreateImage");
      -
      16061  VMA_FETCH_DEVICE_FUNC(vkDestroyImage, PFN_vkDestroyImage, "vkDestroyImage");
      -
      16062  VMA_FETCH_DEVICE_FUNC(vkCmdCopyBuffer, PFN_vkCmdCopyBuffer, "vkCmdCopyBuffer");
      -
      16063 
      -
      16064 #if VMA_VULKAN_VERSION >= 1001000
      -
      16065  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
      -
      16066  {
      -
      16067  VMA_FETCH_DEVICE_FUNC(vkGetBufferMemoryRequirements2KHR, PFN_vkGetBufferMemoryRequirements2, "vkGetBufferMemoryRequirements2");
      -
      16068  VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements2KHR, PFN_vkGetImageMemoryRequirements2, "vkGetImageMemoryRequirements2");
      -
      16069  VMA_FETCH_DEVICE_FUNC(vkBindBufferMemory2KHR, PFN_vkBindBufferMemory2, "vkBindBufferMemory2");
      -
      16070  VMA_FETCH_DEVICE_FUNC(vkBindImageMemory2KHR, PFN_vkBindImageMemory2, "vkBindImageMemory2");
      -
      16071  VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2, "vkGetPhysicalDeviceMemoryProperties2");
      -
      16072  }
      -
      16073 #endif
      +
      15957  VmaMutexLock mutexLock(m_Mutex);
      +
      15958  m_Allocator.Free(hAlloc);
      +
      15959 }
      +
      15960 
      +
      15962 // VmaAllocator_T
      +
      15963 
      +
      15964 VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) :
      +
      15965  m_UseMutex((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT) == 0),
      +
      15966  m_VulkanApiVersion(pCreateInfo->vulkanApiVersion != 0 ? pCreateInfo->vulkanApiVersion : VK_API_VERSION_1_0),
      +
      15967  m_UseKhrDedicatedAllocation((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0),
      +
      15968  m_UseKhrBindMemory2((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0),
      +
      15969  m_UseExtMemoryBudget((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0),
      +
      15970  m_UseAmdDeviceCoherentMemory((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT) != 0),
      +
      15971  m_UseKhrBufferDeviceAddress((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT) != 0),
      +
      15972  m_UseExtMemoryPriority((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT) != 0),
      +
      15973  m_hDevice(pCreateInfo->device),
      +
      15974  m_hInstance(pCreateInfo->instance),
      +
      15975  m_AllocationCallbacksSpecified(pCreateInfo->pAllocationCallbacks != VMA_NULL),
      +
      15976  m_AllocationCallbacks(pCreateInfo->pAllocationCallbacks ?
      +
      15977  *pCreateInfo->pAllocationCallbacks : VmaEmptyAllocationCallbacks),
      +
      15978  m_AllocationObjectAllocator(&m_AllocationCallbacks),
      +
      15979  m_HeapSizeLimitMask(0),
      +
      15980  m_DeviceMemoryCount(0),
      +
      15981  m_PreferredLargeHeapBlockSize(0),
      +
      15982  m_PhysicalDevice(pCreateInfo->physicalDevice),
      +
      15983  m_CurrentFrameIndex(0),
      +
      15984  m_GpuDefragmentationMemoryTypeBits(UINT32_MAX),
      +
      15985  m_NextPoolId(0),
      +
      15986  m_GlobalMemoryTypeBits(UINT32_MAX)
      + +
      15988  ,m_pRecorder(VMA_NULL)
      +
      15989 #endif
      +
      15990 {
      +
      15991  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
      +
      15992  {
      +
      15993  m_UseKhrDedicatedAllocation = false;
      +
      15994  m_UseKhrBindMemory2 = false;
      +
      15995  }
      +
      15996 
      +
      15997  if(VMA_DEBUG_DETECT_CORRUPTION)
      +
      15998  {
      +
      15999  // Needs to be multiply of uint32_t size because we are going to write VMA_CORRUPTION_DETECTION_MAGIC_VALUE to it.
      +
      16000  VMA_ASSERT(VMA_DEBUG_MARGIN % sizeof(uint32_t) == 0);
      +
      16001  }
      +
      16002 
      +
      16003  VMA_ASSERT(pCreateInfo->physicalDevice && pCreateInfo->device && pCreateInfo->instance);
      +
      16004 
      +
      16005  if(m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0))
      +
      16006  {
      +
      16007 #if !(VMA_DEDICATED_ALLOCATION)
      + +
      16009  {
      +
      16010  VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT set but required extensions are disabled by preprocessor macros.");
      +
      16011  }
      +
      16012 #endif
      +
      16013 #if !(VMA_BIND_MEMORY2)
      +
      16014  if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0)
      +
      16015  {
      +
      16016  VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT set but required extension is disabled by preprocessor macros.");
      +
      16017  }
      +
      16018 #endif
      +
      16019  }
      +
      16020 #if !(VMA_MEMORY_BUDGET)
      +
      16021  if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0)
      +
      16022  {
      +
      16023  VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT set but required extension is disabled by preprocessor macros.");
      +
      16024  }
      +
      16025 #endif
      +
      16026 #if !(VMA_BUFFER_DEVICE_ADDRESS)
      +
      16027  if(m_UseKhrBufferDeviceAddress)
      +
      16028  {
      +
      16029  VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT is set but required extension or Vulkan 1.2 is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro.");
      +
      16030  }
      +
      16031 #endif
      +
      16032 #if VMA_VULKAN_VERSION < 1002000
      +
      16033  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 2, 0))
      +
      16034  {
      +
      16035  VMA_ASSERT(0 && "vulkanApiVersion >= VK_API_VERSION_1_2 but required Vulkan version is disabled by preprocessor macros.");
      +
      16036  }
      +
      16037 #endif
      +
      16038 #if VMA_VULKAN_VERSION < 1001000
      +
      16039  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
      +
      16040  {
      +
      16041  VMA_ASSERT(0 && "vulkanApiVersion >= VK_API_VERSION_1_1 but required Vulkan version is disabled by preprocessor macros.");
      +
      16042  }
      +
      16043 #endif
      +
      16044 #if !(VMA_MEMORY_PRIORITY)
      +
      16045  if(m_UseExtMemoryPriority)
      +
      16046  {
      +
      16047  VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro.");
      +
      16048  }
      +
      16049 #endif
      +
      16050 
      +
      16051  memset(&m_DeviceMemoryCallbacks, 0 ,sizeof(m_DeviceMemoryCallbacks));
      +
      16052  memset(&m_PhysicalDeviceProperties, 0, sizeof(m_PhysicalDeviceProperties));
      +
      16053  memset(&m_MemProps, 0, sizeof(m_MemProps));
      +
      16054 
      +
      16055  memset(&m_pBlockVectors, 0, sizeof(m_pBlockVectors));
      +
      16056  memset(&m_VulkanFunctions, 0, sizeof(m_VulkanFunctions));
      +
      16057 
      +
      16058  if(pCreateInfo->pDeviceMemoryCallbacks != VMA_NULL)
      +
      16059  {
      +
      16060  m_DeviceMemoryCallbacks.pUserData = pCreateInfo->pDeviceMemoryCallbacks->pUserData;
      +
      16061  m_DeviceMemoryCallbacks.pfnAllocate = pCreateInfo->pDeviceMemoryCallbacks->pfnAllocate;
      +
      16062  m_DeviceMemoryCallbacks.pfnFree = pCreateInfo->pDeviceMemoryCallbacks->pfnFree;
      +
      16063  }
      +
      16064 
      +
      16065  ImportVulkanFunctions(pCreateInfo->pVulkanFunctions);
      +
      16066 
      +
      16067  (*m_VulkanFunctions.vkGetPhysicalDeviceProperties)(m_PhysicalDevice, &m_PhysicalDeviceProperties);
      +
      16068  (*m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties)(m_PhysicalDevice, &m_MemProps);
      +
      16069 
      +
      16070  VMA_ASSERT(VmaIsPow2(VMA_DEBUG_ALIGNMENT));
      +
      16071  VMA_ASSERT(VmaIsPow2(VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY));
      +
      16072  VMA_ASSERT(VmaIsPow2(m_PhysicalDeviceProperties.limits.bufferImageGranularity));
      +
      16073  VMA_ASSERT(VmaIsPow2(m_PhysicalDeviceProperties.limits.nonCoherentAtomSize));
      16074 
      -
      16075 #if VMA_DEDICATED_ALLOCATION
      -
      16076  if(m_UseKhrDedicatedAllocation)
      -
      16077  {
      -
      16078  VMA_FETCH_DEVICE_FUNC(vkGetBufferMemoryRequirements2KHR, PFN_vkGetBufferMemoryRequirements2KHR, "vkGetBufferMemoryRequirements2KHR");
      -
      16079  VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements2KHR, PFN_vkGetImageMemoryRequirements2KHR, "vkGetImageMemoryRequirements2KHR");
      -
      16080  }
      -
      16081 #endif
      -
      16082 
      -
      16083 #if VMA_BIND_MEMORY2
      -
      16084  if(m_UseKhrBindMemory2)
      -
      16085  {
      -
      16086  VMA_FETCH_DEVICE_FUNC(vkBindBufferMemory2KHR, PFN_vkBindBufferMemory2KHR, "vkBindBufferMemory2KHR");
      -
      16087  VMA_FETCH_DEVICE_FUNC(vkBindImageMemory2KHR, PFN_vkBindImageMemory2KHR, "vkBindImageMemory2KHR");
      -
      16088  }
      -
      16089 #endif // #if VMA_BIND_MEMORY2
      -
      16090 
      -
      16091 #if VMA_MEMORY_BUDGET
      -
      16092  if(m_UseExtMemoryBudget)
      -
      16093  {
      -
      16094  VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2KHR");
      -
      16095  }
      -
      16096 #endif // #if VMA_MEMORY_BUDGET
      -
      16097 
      -
      16098 #undef VMA_FETCH_DEVICE_FUNC
      -
      16099 #undef VMA_FETCH_INSTANCE_FUNC
      -
      16100 }
      -
      16101 
      -
      16102 #endif // #if VMA_DYNAMIC_VULKAN_FUNCTIONS == 1
      -
      16103 
      -
      16104 void VmaAllocator_T::ValidateVulkanFunctions()
      -
      16105 {
      -
      16106  VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceProperties != VMA_NULL);
      -
      16107  VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties != VMA_NULL);
      -
      16108  VMA_ASSERT(m_VulkanFunctions.vkAllocateMemory != VMA_NULL);
      -
      16109  VMA_ASSERT(m_VulkanFunctions.vkFreeMemory != VMA_NULL);
      -
      16110  VMA_ASSERT(m_VulkanFunctions.vkMapMemory != VMA_NULL);
      -
      16111  VMA_ASSERT(m_VulkanFunctions.vkUnmapMemory != VMA_NULL);
      -
      16112  VMA_ASSERT(m_VulkanFunctions.vkFlushMappedMemoryRanges != VMA_NULL);
      -
      16113  VMA_ASSERT(m_VulkanFunctions.vkInvalidateMappedMemoryRanges != VMA_NULL);
      -
      16114  VMA_ASSERT(m_VulkanFunctions.vkBindBufferMemory != VMA_NULL);
      -
      16115  VMA_ASSERT(m_VulkanFunctions.vkBindImageMemory != VMA_NULL);
      -
      16116  VMA_ASSERT(m_VulkanFunctions.vkGetBufferMemoryRequirements != VMA_NULL);
      -
      16117  VMA_ASSERT(m_VulkanFunctions.vkGetImageMemoryRequirements != VMA_NULL);
      -
      16118  VMA_ASSERT(m_VulkanFunctions.vkCreateBuffer != VMA_NULL);
      -
      16119  VMA_ASSERT(m_VulkanFunctions.vkDestroyBuffer != VMA_NULL);
      -
      16120  VMA_ASSERT(m_VulkanFunctions.vkCreateImage != VMA_NULL);
      -
      16121  VMA_ASSERT(m_VulkanFunctions.vkDestroyImage != VMA_NULL);
      -
      16122  VMA_ASSERT(m_VulkanFunctions.vkCmdCopyBuffer != VMA_NULL);
      -
      16123 
      -
      16124 #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
      -
      16125  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0) || m_UseKhrDedicatedAllocation)
      -
      16126  {
      -
      16127  VMA_ASSERT(m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR != VMA_NULL);
      -
      16128  VMA_ASSERT(m_VulkanFunctions.vkGetImageMemoryRequirements2KHR != VMA_NULL);
      -
      16129  }
      -
      16130 #endif
      -
      16131 
      -
      16132 #if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000
      -
      16133  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0) || m_UseKhrBindMemory2)
      -
      16134  {
      -
      16135  VMA_ASSERT(m_VulkanFunctions.vkBindBufferMemory2KHR != VMA_NULL);
      -
      16136  VMA_ASSERT(m_VulkanFunctions.vkBindImageMemory2KHR != VMA_NULL);
      -
      16137  }
      -
      16138 #endif
      -
      16139 
      -
      16140 #if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000
      -
      16141  if(m_UseExtMemoryBudget || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
      -
      16142  {
      -
      16143  VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR != VMA_NULL);
      +
      16075  m_PreferredLargeHeapBlockSize = (pCreateInfo->preferredLargeHeapBlockSize != 0) ?
      +
      16076  pCreateInfo->preferredLargeHeapBlockSize : static_cast<VkDeviceSize>(VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE);
      +
      16077 
      +
      16078  m_GlobalMemoryTypeBits = CalculateGlobalMemoryTypeBits();
      +
      16079 
      +
      16080  if(pCreateInfo->pHeapSizeLimit != VMA_NULL)
      +
      16081  {
      +
      16082  for(uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex)
      +
      16083  {
      +
      16084  const VkDeviceSize limit = pCreateInfo->pHeapSizeLimit[heapIndex];
      +
      16085  if(limit != VK_WHOLE_SIZE)
      +
      16086  {
      +
      16087  m_HeapSizeLimitMask |= 1u << heapIndex;
      +
      16088  if(limit < m_MemProps.memoryHeaps[heapIndex].size)
      +
      16089  {
      +
      16090  m_MemProps.memoryHeaps[heapIndex].size = limit;
      +
      16091  }
      +
      16092  }
      +
      16093  }
      +
      16094  }
      +
      16095 
      +
      16096  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
      +
      16097  {
      +
      16098  const VkDeviceSize preferredBlockSize = CalcPreferredBlockSize(memTypeIndex);
      +
      16099 
      +
      16100  m_pBlockVectors[memTypeIndex] = vma_new(this, VmaBlockVector)(
      +
      16101  this,
      +
      16102  VK_NULL_HANDLE, // hParentPool
      +
      16103  memTypeIndex,
      +
      16104  preferredBlockSize,
      +
      16105  0,
      +
      16106  SIZE_MAX,
      +
      16107  GetBufferImageGranularity(),
      +
      16108  pCreateInfo->frameInUseCount,
      +
      16109  false, // explicitBlockSize
      +
      16110  false, // linearAlgorithm
      +
      16111  0.5f); // priority (0.5 is the default per Vulkan spec)
      +
      16112  // No need to call m_pBlockVectors[memTypeIndex][blockVectorTypeIndex]->CreateMinBlocks here,
      +
      16113  // becase minBlockCount is 0.
      +
      16114  }
      +
      16115 }
      +
      16116 
      +
      16117 VkResult VmaAllocator_T::Init(const VmaAllocatorCreateInfo* pCreateInfo)
      +
      16118 {
      +
      16119  VkResult res = VK_SUCCESS;
      +
      16120 
      +
      16121  if(pCreateInfo->pRecordSettings != VMA_NULL &&
      +
      16122  !VmaStrIsEmpty(pCreateInfo->pRecordSettings->pFilePath))
      +
      16123  {
      +
      16124 #if VMA_RECORDING_ENABLED
      +
      16125  m_pRecorder = vma_new(this, VmaRecorder)();
      +
      16126  res = m_pRecorder->Init(*pCreateInfo->pRecordSettings, m_UseMutex);
      +
      16127  if(res != VK_SUCCESS)
      +
      16128  {
      +
      16129  return res;
      +
      16130  }
      +
      16131  m_pRecorder->WriteConfiguration(
      +
      16132  m_PhysicalDeviceProperties,
      +
      16133  m_MemProps,
      +
      16134  m_VulkanApiVersion,
      +
      16135  m_UseKhrDedicatedAllocation,
      +
      16136  m_UseKhrBindMemory2,
      +
      16137  m_UseExtMemoryBudget,
      +
      16138  m_UseAmdDeviceCoherentMemory);
      +
      16139  m_pRecorder->RecordCreateAllocator(GetCurrentFrameIndex());
      +
      16140 #else
      +
      16141  VMA_ASSERT(0 && "VmaAllocatorCreateInfo::pRecordSettings used, but not supported due to VMA_RECORDING_ENABLED not defined to 1.");
      +
      16142  return VK_ERROR_FEATURE_NOT_PRESENT;
      +
      16143 #endif
      16144  }
      -
      16145 #endif
      -
      16146 }
      -
      16147 
      -
      16148 VkDeviceSize VmaAllocator_T::CalcPreferredBlockSize(uint32_t memTypeIndex)
      -
      16149 {
      -
      16150  const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
      -
      16151  const VkDeviceSize heapSize = m_MemProps.memoryHeaps[heapIndex].size;
      -
      16152  const bool isSmallHeap = heapSize <= VMA_SMALL_HEAP_MAX_SIZE;
      -
      16153  return VmaAlignUp(isSmallHeap ? (heapSize / 8) : m_PreferredLargeHeapBlockSize, (VkDeviceSize)32);
      +
      16145 
      +
      16146 #if VMA_MEMORY_BUDGET
      +
      16147  if(m_UseExtMemoryBudget)
      +
      16148  {
      +
      16149  UpdateVulkanBudget();
      +
      16150  }
      +
      16151 #endif // #if VMA_MEMORY_BUDGET
      +
      16152 
      +
      16153  return res;
      16154 }
      16155 
      -
      16156 VkResult VmaAllocator_T::AllocateMemoryOfType(
      -
      16157  VkDeviceSize size,
      -
      16158  VkDeviceSize alignment,
      -
      16159  bool dedicatedAllocation,
      -
      16160  VkBuffer dedicatedBuffer,
      -
      16161  VkBufferUsageFlags dedicatedBufferUsage,
      -
      16162  VkImage dedicatedImage,
      -
      16163  const VmaAllocationCreateInfo& createInfo,
      -
      16164  uint32_t memTypeIndex,
      -
      16165  VmaSuballocationType suballocType,
      -
      16166  size_t allocationCount,
      -
      16167  VmaAllocation* pAllocations)
      -
      16168 {
      -
      16169  VMA_ASSERT(pAllocations != VMA_NULL);
      -
      16170  VMA_DEBUG_LOG(" AllocateMemory: MemoryTypeIndex=%u, AllocationCount=%zu, Size=%llu", memTypeIndex, allocationCount, size);
      -
      16171 
      -
      16172  VmaAllocationCreateInfo finalCreateInfo = createInfo;
      -
      16173 
      -
      16174  // If memory type is not HOST_VISIBLE, disable MAPPED.
      -
      16175  if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 &&
      -
      16176  (m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
      -
      16177  {
      -
      16178  finalCreateInfo.flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT;
      -
      16179  }
      -
      16180  // If memory is lazily allocated, it should be always dedicated.
      -
      16181  if(finalCreateInfo.usage == VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED)
      -
      16182  {
      - -
      16184  }
      -
      16185 
      -
      16186  VmaBlockVector* const blockVector = m_pBlockVectors[memTypeIndex];
      -
      16187  VMA_ASSERT(blockVector);
      -
      16188 
      -
      16189  const VkDeviceSize preferredBlockSize = blockVector->GetPreferredBlockSize();
      -
      16190  bool preferDedicatedMemory =
      -
      16191  VMA_DEBUG_ALWAYS_DEDICATED_MEMORY ||
      -
      16192  dedicatedAllocation ||
      -
      16193  // Heuristics: Allocate dedicated memory if requested size if greater than half of preferred block size.
      -
      16194  size > preferredBlockSize / 2;
      -
      16195 
      -
      16196  if(preferDedicatedMemory &&
      -
      16197  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0 &&
      -
      16198  finalCreateInfo.pool == VK_NULL_HANDLE)
      -
      16199  {
      - -
      16201  }
      -
      16202 
      -
      16203  if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0)
      -
      16204  {
      -
      16205  if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
      -
      16206  {
      -
      16207  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      -
      16208  }
      -
      16209  else
      -
      16210  {
      -
      16211  return AllocateDedicatedMemory(
      -
      16212  size,
      -
      16213  suballocType,
      -
      16214  memTypeIndex,
      -
      16215  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT) != 0,
      -
      16216  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0,
      -
      16217  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0,
      -
      16218  finalCreateInfo.pUserData,
      -
      16219  finalCreateInfo.priority,
      -
      16220  dedicatedBuffer,
      -
      16221  dedicatedBufferUsage,
      -
      16222  dedicatedImage,
      -
      16223  allocationCount,
      -
      16224  pAllocations);
      -
      16225  }
      -
      16226  }
      -
      16227  else
      -
      16228  {
      -
      16229  VkResult res = blockVector->Allocate(
      -
      16230  m_CurrentFrameIndex.load(),
      -
      16231  size,
      -
      16232  alignment,
      -
      16233  finalCreateInfo,
      -
      16234  suballocType,
      -
      16235  allocationCount,
      -
      16236  pAllocations);
      -
      16237  if(res == VK_SUCCESS)
      -
      16238  {
      -
      16239  return res;
      -
      16240  }
      +
      16156 VmaAllocator_T::~VmaAllocator_T()
      +
      16157 {
      +
      16158 #if VMA_RECORDING_ENABLED
      +
      16159  if(m_pRecorder != VMA_NULL)
      +
      16160  {
      +
      16161  m_pRecorder->RecordDestroyAllocator(GetCurrentFrameIndex());
      +
      16162  vma_delete(this, m_pRecorder);
      +
      16163  }
      +
      16164 #endif
      +
      16165 
      +
      16166  VMA_ASSERT(m_Pools.IsEmpty());
      +
      16167 
      +
      16168  for(size_t memTypeIndex = GetMemoryTypeCount(); memTypeIndex--; )
      +
      16169  {
      +
      16170  if(!m_DedicatedAllocations[memTypeIndex].IsEmpty())
      +
      16171  {
      +
      16172  VMA_ASSERT(0 && "Unfreed dedicated allocations found.");
      +
      16173  }
      +
      16174 
      +
      16175  vma_delete(this, m_pBlockVectors[memTypeIndex]);
      +
      16176  }
      +
      16177 }
      +
      16178 
      +
      16179 void VmaAllocator_T::ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunctions)
      +
      16180 {
      +
      16181 #if VMA_STATIC_VULKAN_FUNCTIONS == 1
      +
      16182  ImportVulkanFunctions_Static();
      +
      16183 #endif
      +
      16184 
      +
      16185  if(pVulkanFunctions != VMA_NULL)
      +
      16186  {
      +
      16187  ImportVulkanFunctions_Custom(pVulkanFunctions);
      +
      16188  }
      +
      16189 
      +
      16190 #if VMA_DYNAMIC_VULKAN_FUNCTIONS == 1
      +
      16191  ImportVulkanFunctions_Dynamic();
      +
      16192 #endif
      +
      16193 
      +
      16194  ValidateVulkanFunctions();
      +
      16195 }
      +
      16196 
      +
      16197 #if VMA_STATIC_VULKAN_FUNCTIONS == 1
      +
      16198 
      +
      16199 void VmaAllocator_T::ImportVulkanFunctions_Static()
      +
      16200 {
      +
      16201  // Vulkan 1.0
      +
      16202  m_VulkanFunctions.vkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties)vkGetPhysicalDeviceProperties;
      +
      16203  m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties)vkGetPhysicalDeviceMemoryProperties;
      +
      16204  m_VulkanFunctions.vkAllocateMemory = (PFN_vkAllocateMemory)vkAllocateMemory;
      +
      16205  m_VulkanFunctions.vkFreeMemory = (PFN_vkFreeMemory)vkFreeMemory;
      +
      16206  m_VulkanFunctions.vkMapMemory = (PFN_vkMapMemory)vkMapMemory;
      +
      16207  m_VulkanFunctions.vkUnmapMemory = (PFN_vkUnmapMemory)vkUnmapMemory;
      +
      16208  m_VulkanFunctions.vkFlushMappedMemoryRanges = (PFN_vkFlushMappedMemoryRanges)vkFlushMappedMemoryRanges;
      +
      16209  m_VulkanFunctions.vkInvalidateMappedMemoryRanges = (PFN_vkInvalidateMappedMemoryRanges)vkInvalidateMappedMemoryRanges;
      +
      16210  m_VulkanFunctions.vkBindBufferMemory = (PFN_vkBindBufferMemory)vkBindBufferMemory;
      +
      16211  m_VulkanFunctions.vkBindImageMemory = (PFN_vkBindImageMemory)vkBindImageMemory;
      +
      16212  m_VulkanFunctions.vkGetBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements)vkGetBufferMemoryRequirements;
      +
      16213  m_VulkanFunctions.vkGetImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)vkGetImageMemoryRequirements;
      +
      16214  m_VulkanFunctions.vkCreateBuffer = (PFN_vkCreateBuffer)vkCreateBuffer;
      +
      16215  m_VulkanFunctions.vkDestroyBuffer = (PFN_vkDestroyBuffer)vkDestroyBuffer;
      +
      16216  m_VulkanFunctions.vkCreateImage = (PFN_vkCreateImage)vkCreateImage;
      +
      16217  m_VulkanFunctions.vkDestroyImage = (PFN_vkDestroyImage)vkDestroyImage;
      +
      16218  m_VulkanFunctions.vkCmdCopyBuffer = (PFN_vkCmdCopyBuffer)vkCmdCopyBuffer;
      +
      16219 
      +
      16220  // Vulkan 1.1
      +
      16221 #if VMA_VULKAN_VERSION >= 1001000
      +
      16222  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
      +
      16223  {
      +
      16224  m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR = (PFN_vkGetBufferMemoryRequirements2)vkGetBufferMemoryRequirements2;
      +
      16225  m_VulkanFunctions.vkGetImageMemoryRequirements2KHR = (PFN_vkGetImageMemoryRequirements2)vkGetImageMemoryRequirements2;
      +
      16226  m_VulkanFunctions.vkBindBufferMemory2KHR = (PFN_vkBindBufferMemory2)vkBindBufferMemory2;
      +
      16227  m_VulkanFunctions.vkBindImageMemory2KHR = (PFN_vkBindImageMemory2)vkBindImageMemory2;
      +
      16228  m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR = (PFN_vkGetPhysicalDeviceMemoryProperties2)vkGetPhysicalDeviceMemoryProperties2;
      +
      16229  }
      +
      16230 #endif
      +
      16231 }
      +
      16232 
      +
      16233 #endif // #if VMA_STATIC_VULKAN_FUNCTIONS == 1
      +
      16234 
      +
      16235 void VmaAllocator_T::ImportVulkanFunctions_Custom(const VmaVulkanFunctions* pVulkanFunctions)
      +
      16236 {
      +
      16237  VMA_ASSERT(pVulkanFunctions != VMA_NULL);
      +
      16238 
      +
      16239 #define VMA_COPY_IF_NOT_NULL(funcName) \
      +
      16240  if(pVulkanFunctions->funcName != VMA_NULL) m_VulkanFunctions.funcName = pVulkanFunctions->funcName;
      16241 
      -
      16242  // 5. Try dedicated memory.
      -
      16243  if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
      -
      16244  {
      -
      16245  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      -
      16246  }
      -
      16247  else
      -
      16248  {
      -
      16249  res = AllocateDedicatedMemory(
      -
      16250  size,
      -
      16251  suballocType,
      -
      16252  memTypeIndex,
      -
      16253  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT) != 0,
      -
      16254  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0,
      -
      16255  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0,
      -
      16256  finalCreateInfo.pUserData,
      -
      16257  finalCreateInfo.priority,
      -
      16258  dedicatedBuffer,
      -
      16259  dedicatedBufferUsage,
      -
      16260  dedicatedImage,
      -
      16261  allocationCount,
      -
      16262  pAllocations);
      -
      16263  if(res == VK_SUCCESS)
      -
      16264  {
      -
      16265  // Succeeded: AllocateDedicatedMemory function already filld pMemory, nothing more to do here.
      -
      16266  VMA_DEBUG_LOG(" Allocated as DedicatedMemory");
      -
      16267  return VK_SUCCESS;
      -
      16268  }
      -
      16269  else
      -
      16270  {
      -
      16271  // Everything failed: Return error code.
      -
      16272  VMA_DEBUG_LOG(" vkAllocateMemory FAILED");
      -
      16273  return res;
      -
      16274  }
      -
      16275  }
      -
      16276  }
      -
      16277 }
      +
      16242  VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceProperties);
      +
      16243  VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceMemoryProperties);
      +
      16244  VMA_COPY_IF_NOT_NULL(vkAllocateMemory);
      +
      16245  VMA_COPY_IF_NOT_NULL(vkFreeMemory);
      +
      16246  VMA_COPY_IF_NOT_NULL(vkMapMemory);
      +
      16247  VMA_COPY_IF_NOT_NULL(vkUnmapMemory);
      +
      16248  VMA_COPY_IF_NOT_NULL(vkFlushMappedMemoryRanges);
      +
      16249  VMA_COPY_IF_NOT_NULL(vkInvalidateMappedMemoryRanges);
      +
      16250  VMA_COPY_IF_NOT_NULL(vkBindBufferMemory);
      +
      16251  VMA_COPY_IF_NOT_NULL(vkBindImageMemory);
      +
      16252  VMA_COPY_IF_NOT_NULL(vkGetBufferMemoryRequirements);
      +
      16253  VMA_COPY_IF_NOT_NULL(vkGetImageMemoryRequirements);
      +
      16254  VMA_COPY_IF_NOT_NULL(vkCreateBuffer);
      +
      16255  VMA_COPY_IF_NOT_NULL(vkDestroyBuffer);
      +
      16256  VMA_COPY_IF_NOT_NULL(vkCreateImage);
      +
      16257  VMA_COPY_IF_NOT_NULL(vkDestroyImage);
      +
      16258  VMA_COPY_IF_NOT_NULL(vkCmdCopyBuffer);
      +
      16259 
      +
      16260 #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
      +
      16261  VMA_COPY_IF_NOT_NULL(vkGetBufferMemoryRequirements2KHR);
      +
      16262  VMA_COPY_IF_NOT_NULL(vkGetImageMemoryRequirements2KHR);
      +
      16263 #endif
      +
      16264 
      +
      16265 #if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000
      +
      16266  VMA_COPY_IF_NOT_NULL(vkBindBufferMemory2KHR);
      +
      16267  VMA_COPY_IF_NOT_NULL(vkBindImageMemory2KHR);
      +
      16268 #endif
      +
      16269 
      +
      16270 #if VMA_MEMORY_BUDGET
      +
      16271  VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceMemoryProperties2KHR);
      +
      16272 #endif
      +
      16273 
      +
      16274 #undef VMA_COPY_IF_NOT_NULL
      +
      16275 }
      +
      16276 
      +
      16277 #if VMA_DYNAMIC_VULKAN_FUNCTIONS == 1
      16278 
      -
      16279 VkResult VmaAllocator_T::AllocateDedicatedMemory(
      -
      16280  VkDeviceSize size,
      -
      16281  VmaSuballocationType suballocType,
      -
      16282  uint32_t memTypeIndex,
      -
      16283  bool withinBudget,
      -
      16284  bool map,
      -
      16285  bool isUserDataString,
      -
      16286  void* pUserData,
      -
      16287  float priority,
      -
      16288  VkBuffer dedicatedBuffer,
      -
      16289  VkBufferUsageFlags dedicatedBufferUsage,
      -
      16290  VkImage dedicatedImage,
      -
      16291  size_t allocationCount,
      -
      16292  VmaAllocation* pAllocations)
      -
      16293 {
      -
      16294  VMA_ASSERT(allocationCount > 0 && pAllocations);
      -
      16295 
      -
      16296  if(withinBudget)
      -
      16297  {
      -
      16298  const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
      -
      16299  VmaBudget heapBudget = {};
      -
      16300  GetBudget(&heapBudget, heapIndex, 1);
      -
      16301  if(heapBudget.usage + size * allocationCount > heapBudget.budget)
      -
      16302  {
      -
      16303  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      -
      16304  }
      -
      16305  }
      -
      16306 
      -
      16307  VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
      -
      16308  allocInfo.memoryTypeIndex = memTypeIndex;
      -
      16309  allocInfo.allocationSize = size;
      -
      16310 
      -
      16311 #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
      -
      16312  VkMemoryDedicatedAllocateInfoKHR dedicatedAllocInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR };
      -
      16313  if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
      -
      16314  {
      -
      16315  if(dedicatedBuffer != VK_NULL_HANDLE)
      -
      16316  {
      -
      16317  VMA_ASSERT(dedicatedImage == VK_NULL_HANDLE);
      -
      16318  dedicatedAllocInfo.buffer = dedicatedBuffer;
      -
      16319  VmaPnextChainPushFront(&allocInfo, &dedicatedAllocInfo);
      -
      16320  }
      -
      16321  else if(dedicatedImage != VK_NULL_HANDLE)
      -
      16322  {
      -
      16323  dedicatedAllocInfo.image = dedicatedImage;
      -
      16324  VmaPnextChainPushFront(&allocInfo, &dedicatedAllocInfo);
      -
      16325  }
      -
      16326  }
      -
      16327 #endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
      -
      16328 
      -
      16329 #if VMA_BUFFER_DEVICE_ADDRESS
      -
      16330  VkMemoryAllocateFlagsInfoKHR allocFlagsInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR };
      -
      16331  if(m_UseKhrBufferDeviceAddress)
      -
      16332  {
      -
      16333  bool canContainBufferWithDeviceAddress = true;
      -
      16334  if(dedicatedBuffer != VK_NULL_HANDLE)
      -
      16335  {
      -
      16336  canContainBufferWithDeviceAddress = dedicatedBufferUsage == UINT32_MAX || // Usage flags unknown
      -
      16337  (dedicatedBufferUsage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT) != 0;
      -
      16338  }
      -
      16339  else if(dedicatedImage != VK_NULL_HANDLE)
      -
      16340  {
      -
      16341  canContainBufferWithDeviceAddress = false;
      -
      16342  }
      -
      16343  if(canContainBufferWithDeviceAddress)
      -
      16344  {
      -
      16345  allocFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
      -
      16346  VmaPnextChainPushFront(&allocInfo, &allocFlagsInfo);
      -
      16347  }
      -
      16348  }
      -
      16349 #endif // #if VMA_BUFFER_DEVICE_ADDRESS
      -
      16350 
      -
      16351 #if VMA_MEMORY_PRIORITY
      -
      16352  VkMemoryPriorityAllocateInfoEXT priorityInfo = { VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT };
      -
      16353  if(m_UseExtMemoryPriority)
      -
      16354  {
      -
      16355  priorityInfo.priority = priority;
      -
      16356  VmaPnextChainPushFront(&allocInfo, &priorityInfo);
      -
      16357  }
      -
      16358 #endif // #if VMA_MEMORY_PRIORITY
      -
      16359 
      -
      16360  size_t allocIndex;
      -
      16361  VkResult res = VK_SUCCESS;
      -
      16362  for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
      -
      16363  {
      -
      16364  res = AllocateDedicatedMemoryPage(
      -
      16365  size,
      -
      16366  suballocType,
      -
      16367  memTypeIndex,
      -
      16368  allocInfo,
      -
      16369  map,
      -
      16370  isUserDataString,
      -
      16371  pUserData,
      -
      16372  pAllocations + allocIndex);
      -
      16373  if(res != VK_SUCCESS)
      -
      16374  {
      -
      16375  break;
      -
      16376  }
      -
      16377  }
      -
      16378 
      -
      16379  if(res == VK_SUCCESS)
      -
      16380  {
      -
      16381  // Register them in m_pDedicatedAllocations.
      -
      16382  {
      -
      16383  VmaMutexLockWrite lock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
      -
      16384  AllocationVectorType* pDedicatedAllocations = m_pDedicatedAllocations[memTypeIndex];
      -
      16385  VMA_ASSERT(pDedicatedAllocations);
      -
      16386  for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
      -
      16387  {
      -
      16388  VmaVectorInsertSorted<VmaPointerLess>(*pDedicatedAllocations, pAllocations[allocIndex]);
      -
      16389  }
      -
      16390  }
      +
      16279 void VmaAllocator_T::ImportVulkanFunctions_Dynamic()
      +
      16280 {
      +
      16281 #define VMA_FETCH_INSTANCE_FUNC(memberName, functionPointerType, functionNameString) \
      +
      16282  if(m_VulkanFunctions.memberName == VMA_NULL) \
      +
      16283  m_VulkanFunctions.memberName = \
      +
      16284  (functionPointerType)vkGetInstanceProcAddr(m_hInstance, functionNameString);
      +
      16285 #define VMA_FETCH_DEVICE_FUNC(memberName, functionPointerType, functionNameString) \
      +
      16286  if(m_VulkanFunctions.memberName == VMA_NULL) \
      +
      16287  m_VulkanFunctions.memberName = \
      +
      16288  (functionPointerType)vkGetDeviceProcAddr(m_hDevice, functionNameString);
      +
      16289 
      +
      16290  VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceProperties, PFN_vkGetPhysicalDeviceProperties, "vkGetPhysicalDeviceProperties");
      +
      16291  VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties, PFN_vkGetPhysicalDeviceMemoryProperties, "vkGetPhysicalDeviceMemoryProperties");
      +
      16292  VMA_FETCH_DEVICE_FUNC(vkAllocateMemory, PFN_vkAllocateMemory, "vkAllocateMemory");
      +
      16293  VMA_FETCH_DEVICE_FUNC(vkFreeMemory, PFN_vkFreeMemory, "vkFreeMemory");
      +
      16294  VMA_FETCH_DEVICE_FUNC(vkMapMemory, PFN_vkMapMemory, "vkMapMemory");
      +
      16295  VMA_FETCH_DEVICE_FUNC(vkUnmapMemory, PFN_vkUnmapMemory, "vkUnmapMemory");
      +
      16296  VMA_FETCH_DEVICE_FUNC(vkFlushMappedMemoryRanges, PFN_vkFlushMappedMemoryRanges, "vkFlushMappedMemoryRanges");
      +
      16297  VMA_FETCH_DEVICE_FUNC(vkInvalidateMappedMemoryRanges, PFN_vkInvalidateMappedMemoryRanges, "vkInvalidateMappedMemoryRanges");
      +
      16298  VMA_FETCH_DEVICE_FUNC(vkBindBufferMemory, PFN_vkBindBufferMemory, "vkBindBufferMemory");
      +
      16299  VMA_FETCH_DEVICE_FUNC(vkBindImageMemory, PFN_vkBindImageMemory, "vkBindImageMemory");
      +
      16300  VMA_FETCH_DEVICE_FUNC(vkGetBufferMemoryRequirements, PFN_vkGetBufferMemoryRequirements, "vkGetBufferMemoryRequirements");
      +
      16301  VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements, PFN_vkGetImageMemoryRequirements, "vkGetImageMemoryRequirements");
      +
      16302  VMA_FETCH_DEVICE_FUNC(vkCreateBuffer, PFN_vkCreateBuffer, "vkCreateBuffer");
      +
      16303  VMA_FETCH_DEVICE_FUNC(vkDestroyBuffer, PFN_vkDestroyBuffer, "vkDestroyBuffer");
      +
      16304  VMA_FETCH_DEVICE_FUNC(vkCreateImage, PFN_vkCreateImage, "vkCreateImage");
      +
      16305  VMA_FETCH_DEVICE_FUNC(vkDestroyImage, PFN_vkDestroyImage, "vkDestroyImage");
      +
      16306  VMA_FETCH_DEVICE_FUNC(vkCmdCopyBuffer, PFN_vkCmdCopyBuffer, "vkCmdCopyBuffer");
      +
      16307 
      +
      16308 #if VMA_VULKAN_VERSION >= 1001000
      +
      16309  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
      +
      16310  {
      +
      16311  VMA_FETCH_DEVICE_FUNC(vkGetBufferMemoryRequirements2KHR, PFN_vkGetBufferMemoryRequirements2, "vkGetBufferMemoryRequirements2");
      +
      16312  VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements2KHR, PFN_vkGetImageMemoryRequirements2, "vkGetImageMemoryRequirements2");
      +
      16313  VMA_FETCH_DEVICE_FUNC(vkBindBufferMemory2KHR, PFN_vkBindBufferMemory2, "vkBindBufferMemory2");
      +
      16314  VMA_FETCH_DEVICE_FUNC(vkBindImageMemory2KHR, PFN_vkBindImageMemory2, "vkBindImageMemory2");
      +
      16315  VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2, "vkGetPhysicalDeviceMemoryProperties2");
      +
      16316  }
      +
      16317 #endif
      +
      16318 
      +
      16319 #if VMA_DEDICATED_ALLOCATION
      +
      16320  if(m_UseKhrDedicatedAllocation)
      +
      16321  {
      +
      16322  VMA_FETCH_DEVICE_FUNC(vkGetBufferMemoryRequirements2KHR, PFN_vkGetBufferMemoryRequirements2KHR, "vkGetBufferMemoryRequirements2KHR");
      +
      16323  VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements2KHR, PFN_vkGetImageMemoryRequirements2KHR, "vkGetImageMemoryRequirements2KHR");
      +
      16324  }
      +
      16325 #endif
      +
      16326 
      +
      16327 #if VMA_BIND_MEMORY2
      +
      16328  if(m_UseKhrBindMemory2)
      +
      16329  {
      +
      16330  VMA_FETCH_DEVICE_FUNC(vkBindBufferMemory2KHR, PFN_vkBindBufferMemory2KHR, "vkBindBufferMemory2KHR");
      +
      16331  VMA_FETCH_DEVICE_FUNC(vkBindImageMemory2KHR, PFN_vkBindImageMemory2KHR, "vkBindImageMemory2KHR");
      +
      16332  }
      +
      16333 #endif // #if VMA_BIND_MEMORY2
      +
      16334 
      +
      16335 #if VMA_MEMORY_BUDGET
      +
      16336  if(m_UseExtMemoryBudget)
      +
      16337  {
      +
      16338  VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2KHR");
      +
      16339  }
      +
      16340 #endif // #if VMA_MEMORY_BUDGET
      +
      16341 
      +
      16342 #undef VMA_FETCH_DEVICE_FUNC
      +
      16343 #undef VMA_FETCH_INSTANCE_FUNC
      +
      16344 }
      +
      16345 
      +
      16346 #endif // #if VMA_DYNAMIC_VULKAN_FUNCTIONS == 1
      +
      16347 
      +
      16348 void VmaAllocator_T::ValidateVulkanFunctions()
      +
      16349 {
      +
      16350  VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceProperties != VMA_NULL);
      +
      16351  VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties != VMA_NULL);
      +
      16352  VMA_ASSERT(m_VulkanFunctions.vkAllocateMemory != VMA_NULL);
      +
      16353  VMA_ASSERT(m_VulkanFunctions.vkFreeMemory != VMA_NULL);
      +
      16354  VMA_ASSERT(m_VulkanFunctions.vkMapMemory != VMA_NULL);
      +
      16355  VMA_ASSERT(m_VulkanFunctions.vkUnmapMemory != VMA_NULL);
      +
      16356  VMA_ASSERT(m_VulkanFunctions.vkFlushMappedMemoryRanges != VMA_NULL);
      +
      16357  VMA_ASSERT(m_VulkanFunctions.vkInvalidateMappedMemoryRanges != VMA_NULL);
      +
      16358  VMA_ASSERT(m_VulkanFunctions.vkBindBufferMemory != VMA_NULL);
      +
      16359  VMA_ASSERT(m_VulkanFunctions.vkBindImageMemory != VMA_NULL);
      +
      16360  VMA_ASSERT(m_VulkanFunctions.vkGetBufferMemoryRequirements != VMA_NULL);
      +
      16361  VMA_ASSERT(m_VulkanFunctions.vkGetImageMemoryRequirements != VMA_NULL);
      +
      16362  VMA_ASSERT(m_VulkanFunctions.vkCreateBuffer != VMA_NULL);
      +
      16363  VMA_ASSERT(m_VulkanFunctions.vkDestroyBuffer != VMA_NULL);
      +
      16364  VMA_ASSERT(m_VulkanFunctions.vkCreateImage != VMA_NULL);
      +
      16365  VMA_ASSERT(m_VulkanFunctions.vkDestroyImage != VMA_NULL);
      +
      16366  VMA_ASSERT(m_VulkanFunctions.vkCmdCopyBuffer != VMA_NULL);
      +
      16367 
      +
      16368 #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
      +
      16369  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0) || m_UseKhrDedicatedAllocation)
      +
      16370  {
      +
      16371  VMA_ASSERT(m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR != VMA_NULL);
      +
      16372  VMA_ASSERT(m_VulkanFunctions.vkGetImageMemoryRequirements2KHR != VMA_NULL);
      +
      16373  }
      +
      16374 #endif
      +
      16375 
      +
      16376 #if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000
      +
      16377  if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0) || m_UseKhrBindMemory2)
      +
      16378  {
      +
      16379  VMA_ASSERT(m_VulkanFunctions.vkBindBufferMemory2KHR != VMA_NULL);
      +
      16380  VMA_ASSERT(m_VulkanFunctions.vkBindImageMemory2KHR != VMA_NULL);
      +
      16381  }
      +
      16382 #endif
      +
      16383 
      +
      16384 #if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000
      +
      16385  if(m_UseExtMemoryBudget || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
      +
      16386  {
      +
      16387  VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR != VMA_NULL);
      +
      16388  }
      +
      16389 #endif
      +
      16390 }
      16391 
      -
      16392  VMA_DEBUG_LOG(" Allocated DedicatedMemory Count=%zu, MemoryTypeIndex=#%u", allocationCount, memTypeIndex);
      -
      16393  }
      -
      16394  else
      -
      16395  {
      -
      16396  // Free all already created allocations.
      -
      16397  while(allocIndex--)
      -
      16398  {
      -
      16399  VmaAllocation currAlloc = pAllocations[allocIndex];
      -
      16400  VkDeviceMemory hMemory = currAlloc->GetMemory();
      -
      16401 
      -
      16402  /*
      -
      16403  There is no need to call this, because Vulkan spec allows to skip vkUnmapMemory
      -
      16404  before vkFreeMemory.
      -
      16405 
      -
      16406  if(currAlloc->GetMappedData() != VMA_NULL)
      -
      16407  {
      -
      16408  (*m_VulkanFunctions.vkUnmapMemory)(m_hDevice, hMemory);
      -
      16409  }
      -
      16410  */
      -
      16411 
      -
      16412  FreeVulkanMemory(memTypeIndex, currAlloc->GetSize(), hMemory);
      -
      16413  m_Budget.RemoveAllocation(MemoryTypeIndexToHeapIndex(memTypeIndex), currAlloc->GetSize());
      -
      16414  currAlloc->SetUserData(this, VMA_NULL);
      -
      16415  m_AllocationObjectAllocator.Free(currAlloc);
      -
      16416  }
      +
      16392 VkDeviceSize VmaAllocator_T::CalcPreferredBlockSize(uint32_t memTypeIndex)
      +
      16393 {
      +
      16394  const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
      +
      16395  const VkDeviceSize heapSize = m_MemProps.memoryHeaps[heapIndex].size;
      +
      16396  const bool isSmallHeap = heapSize <= VMA_SMALL_HEAP_MAX_SIZE;
      +
      16397  return VmaAlignUp(isSmallHeap ? (heapSize / 8) : m_PreferredLargeHeapBlockSize, (VkDeviceSize)32);
      +
      16398 }
      +
      16399 
      +
      16400 VkResult VmaAllocator_T::AllocateMemoryOfType(
      +
      16401  VkDeviceSize size,
      +
      16402  VkDeviceSize alignment,
      +
      16403  bool dedicatedAllocation,
      +
      16404  VkBuffer dedicatedBuffer,
      +
      16405  VkBufferUsageFlags dedicatedBufferUsage,
      +
      16406  VkImage dedicatedImage,
      +
      16407  const VmaAllocationCreateInfo& createInfo,
      +
      16408  uint32_t memTypeIndex,
      +
      16409  VmaSuballocationType suballocType,
      +
      16410  size_t allocationCount,
      +
      16411  VmaAllocation* pAllocations)
      +
      16412 {
      +
      16413  VMA_ASSERT(pAllocations != VMA_NULL);
      +
      16414  VMA_DEBUG_LOG(" AllocateMemory: MemoryTypeIndex=%u, AllocationCount=%zu, Size=%llu", memTypeIndex, allocationCount, size);
      +
      16415 
      +
      16416  VmaAllocationCreateInfo finalCreateInfo = createInfo;
      16417 
      -
      16418  memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount);
      -
      16419  }
      -
      16420 
      -
      16421  return res;
      -
      16422 }
      -
      16423 
      -
      16424 VkResult VmaAllocator_T::AllocateDedicatedMemoryPage(
      -
      16425  VkDeviceSize size,
      -
      16426  VmaSuballocationType suballocType,
      -
      16427  uint32_t memTypeIndex,
      -
      16428  const VkMemoryAllocateInfo& allocInfo,
      -
      16429  bool map,
      -
      16430  bool isUserDataString,
      -
      16431  void* pUserData,
      -
      16432  VmaAllocation* pAllocation)
      -
      16433 {
      -
      16434  VkDeviceMemory hMemory = VK_NULL_HANDLE;
      -
      16435  VkResult res = AllocateVulkanMemory(&allocInfo, &hMemory);
      -
      16436  if(res < 0)
      -
      16437  {
      -
      16438  VMA_DEBUG_LOG(" vkAllocateMemory FAILED");
      -
      16439  return res;
      -
      16440  }
      -
      16441 
      -
      16442  void* pMappedData = VMA_NULL;
      -
      16443  if(map)
      -
      16444  {
      -
      16445  res = (*m_VulkanFunctions.vkMapMemory)(
      -
      16446  m_hDevice,
      -
      16447  hMemory,
      -
      16448  0,
      -
      16449  VK_WHOLE_SIZE,
      -
      16450  0,
      -
      16451  &pMappedData);
      -
      16452  if(res < 0)
      -
      16453  {
      -
      16454  VMA_DEBUG_LOG(" vkMapMemory FAILED");
      -
      16455  FreeVulkanMemory(memTypeIndex, size, hMemory);
      -
      16456  return res;
      -
      16457  }
      -
      16458  }
      -
      16459 
      -
      16460  *pAllocation = m_AllocationObjectAllocator.Allocate(m_CurrentFrameIndex.load(), isUserDataString);
      -
      16461  (*pAllocation)->InitDedicatedAllocation(memTypeIndex, hMemory, suballocType, pMappedData, size);
      -
      16462  (*pAllocation)->SetUserData(this, pUserData);
      -
      16463  m_Budget.AddAllocation(MemoryTypeIndexToHeapIndex(memTypeIndex), size);
      -
      16464  if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
      -
      16465  {
      -
      16466  FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED);
      -
      16467  }
      -
      16468 
      -
      16469  return VK_SUCCESS;
      -
      16470 }
      -
      16471 
      -
      16472 void VmaAllocator_T::GetBufferMemoryRequirements(
      -
      16473  VkBuffer hBuffer,
      -
      16474  VkMemoryRequirements& memReq,
      -
      16475  bool& requiresDedicatedAllocation,
      -
      16476  bool& prefersDedicatedAllocation) const
      -
      16477 {
      -
      16478 #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
      -
      16479  if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
      -
      16480  {
      -
      16481  VkBufferMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR };
      -
      16482  memReqInfo.buffer = hBuffer;
      -
      16483 
      -
      16484  VkMemoryDedicatedRequirementsKHR memDedicatedReq = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR };
      +
      16418  // If memory type is not HOST_VISIBLE, disable MAPPED.
      +
      16419  if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 &&
      +
      16420  (m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
      +
      16421  {
      +
      16422  finalCreateInfo.flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT;
      +
      16423  }
      +
      16424  // If memory is lazily allocated, it should be always dedicated.
      +
      16425  if(finalCreateInfo.usage == VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED)
      +
      16426  {
      + +
      16428  }
      +
      16429 
      +
      16430  VmaBlockVector* const blockVector = m_pBlockVectors[memTypeIndex];
      +
      16431  VMA_ASSERT(blockVector);
      +
      16432 
      +
      16433  const VkDeviceSize preferredBlockSize = blockVector->GetPreferredBlockSize();
      +
      16434  bool preferDedicatedMemory =
      +
      16435  VMA_DEBUG_ALWAYS_DEDICATED_MEMORY ||
      +
      16436  dedicatedAllocation ||
      +
      16437  // Heuristics: Allocate dedicated memory if requested size if greater than half of preferred block size.
      +
      16438  size > preferredBlockSize / 2;
      +
      16439 
      +
      16440  if(preferDedicatedMemory &&
      +
      16441  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0 &&
      +
      16442  finalCreateInfo.pool == VK_NULL_HANDLE)
      +
      16443  {
      + +
      16445  }
      +
      16446 
      +
      16447  if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0)
      +
      16448  {
      +
      16449  if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
      +
      16450  {
      +
      16451  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      +
      16452  }
      +
      16453  else
      +
      16454  {
      +
      16455  return AllocateDedicatedMemory(
      +
      16456  size,
      +
      16457  suballocType,
      +
      16458  memTypeIndex,
      +
      16459  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT) != 0,
      +
      16460  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0,
      +
      16461  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0,
      +
      16462  finalCreateInfo.pUserData,
      +
      16463  finalCreateInfo.priority,
      +
      16464  dedicatedBuffer,
      +
      16465  dedicatedBufferUsage,
      +
      16466  dedicatedImage,
      +
      16467  allocationCount,
      +
      16468  pAllocations);
      +
      16469  }
      +
      16470  }
      +
      16471  else
      +
      16472  {
      +
      16473  VkResult res = blockVector->Allocate(
      +
      16474  m_CurrentFrameIndex.load(),
      +
      16475  size,
      +
      16476  alignment,
      +
      16477  finalCreateInfo,
      +
      16478  suballocType,
      +
      16479  allocationCount,
      +
      16480  pAllocations);
      +
      16481  if(res == VK_SUCCESS)
      +
      16482  {
      +
      16483  return res;
      +
      16484  }
      16485 
      -
      16486  VkMemoryRequirements2KHR memReq2 = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR };
      -
      16487  VmaPnextChainPushFront(&memReq2, &memDedicatedReq);
      -
      16488 
      -
      16489  (*m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR)(m_hDevice, &memReqInfo, &memReq2);
      -
      16490 
      -
      16491  memReq = memReq2.memoryRequirements;
      -
      16492  requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE);
      -
      16493  prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE);
      -
      16494  }
      -
      16495  else
      -
      16496 #endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
      -
      16497  {
      -
      16498  (*m_VulkanFunctions.vkGetBufferMemoryRequirements)(m_hDevice, hBuffer, &memReq);
      -
      16499  requiresDedicatedAllocation = false;
      -
      16500  prefersDedicatedAllocation = false;
      -
      16501  }
      -
      16502 }
      -
      16503 
      -
      16504 void VmaAllocator_T::GetImageMemoryRequirements(
      -
      16505  VkImage hImage,
      -
      16506  VkMemoryRequirements& memReq,
      -
      16507  bool& requiresDedicatedAllocation,
      -
      16508  bool& prefersDedicatedAllocation) const
      -
      16509 {
      -
      16510 #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
      -
      16511  if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
      -
      16512  {
      -
      16513  VkImageMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR };
      -
      16514  memReqInfo.image = hImage;
      -
      16515 
      -
      16516  VkMemoryDedicatedRequirementsKHR memDedicatedReq = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR };
      -
      16517 
      -
      16518  VkMemoryRequirements2KHR memReq2 = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR };
      -
      16519  VmaPnextChainPushFront(&memReq2, &memDedicatedReq);
      -
      16520 
      -
      16521  (*m_VulkanFunctions.vkGetImageMemoryRequirements2KHR)(m_hDevice, &memReqInfo, &memReq2);
      -
      16522 
      -
      16523  memReq = memReq2.memoryRequirements;
      -
      16524  requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE);
      -
      16525  prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE);
      +
      16486  // 5. Try dedicated memory.
      +
      16487  if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
      +
      16488  {
      +
      16489  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      +
      16490  }
      +
      16491 
      +
      16492  // Protection against creating each allocation as dedicated when we reach or exceed heap size/budget,
      +
      16493  // which can quickly deplete maxMemoryAllocationCount: Don't try dedicated allocations when above
      +
      16494  // 3/4 of the maximum allocation count.
      +
      16495  if(m_DeviceMemoryCount.load() > m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount * 3 / 4)
      +
      16496  {
      +
      16497  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      +
      16498  }
      +
      16499 
      +
      16500  res = AllocateDedicatedMemory(
      +
      16501  size,
      +
      16502  suballocType,
      +
      16503  memTypeIndex,
      +
      16504  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT) != 0,
      +
      16505  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0,
      +
      16506  (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0,
      +
      16507  finalCreateInfo.pUserData,
      +
      16508  finalCreateInfo.priority,
      +
      16509  dedicatedBuffer,
      +
      16510  dedicatedBufferUsage,
      +
      16511  dedicatedImage,
      +
      16512  allocationCount,
      +
      16513  pAllocations);
      +
      16514  if(res == VK_SUCCESS)
      +
      16515  {
      +
      16516  // Succeeded: AllocateDedicatedMemory function already filld pMemory, nothing more to do here.
      +
      16517  VMA_DEBUG_LOG(" Allocated as DedicatedMemory");
      +
      16518  return VK_SUCCESS;
      +
      16519  }
      +
      16520  else
      +
      16521  {
      +
      16522  // Everything failed: Return error code.
      +
      16523  VMA_DEBUG_LOG(" vkAllocateMemory FAILED");
      +
      16524  return res;
      +
      16525  }
      16526  }
      -
      16527  else
      -
      16528 #endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
      -
      16529  {
      -
      16530  (*m_VulkanFunctions.vkGetImageMemoryRequirements)(m_hDevice, hImage, &memReq);
      -
      16531  requiresDedicatedAllocation = false;
      -
      16532  prefersDedicatedAllocation = false;
      -
      16533  }
      -
      16534 }
      -
      16535 
      -
      16536 VkResult VmaAllocator_T::AllocateMemory(
      -
      16537  const VkMemoryRequirements& vkMemReq,
      -
      16538  bool requiresDedicatedAllocation,
      -
      16539  bool prefersDedicatedAllocation,
      -
      16540  VkBuffer dedicatedBuffer,
      -
      16541  VkBufferUsageFlags dedicatedBufferUsage,
      -
      16542  VkImage dedicatedImage,
      -
      16543  const VmaAllocationCreateInfo& createInfo,
      -
      16544  VmaSuballocationType suballocType,
      -
      16545  size_t allocationCount,
      -
      16546  VmaAllocation* pAllocations)
      -
      16547 {
      -
      16548  memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount);
      -
      16549 
      -
      16550  VMA_ASSERT(VmaIsPow2(vkMemReq.alignment));
      -
      16551 
      -
      16552  if(vkMemReq.size == 0)
      -
      16553  {
      -
      16554  return VK_ERROR_VALIDATION_FAILED_EXT;
      +
      16527 }
      +
      16528 
      +
      16529 VkResult VmaAllocator_T::AllocateDedicatedMemory(
      +
      16530  VkDeviceSize size,
      +
      16531  VmaSuballocationType suballocType,
      +
      16532  uint32_t memTypeIndex,
      +
      16533  bool withinBudget,
      +
      16534  bool map,
      +
      16535  bool isUserDataString,
      +
      16536  void* pUserData,
      +
      16537  float priority,
      +
      16538  VkBuffer dedicatedBuffer,
      +
      16539  VkBufferUsageFlags dedicatedBufferUsage,
      +
      16540  VkImage dedicatedImage,
      +
      16541  size_t allocationCount,
      +
      16542  VmaAllocation* pAllocations)
      +
      16543 {
      +
      16544  VMA_ASSERT(allocationCount > 0 && pAllocations);
      +
      16545 
      +
      16546  if(withinBudget)
      +
      16547  {
      +
      16548  const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
      +
      16549  VmaBudget heapBudget = {};
      +
      16550  GetBudget(&heapBudget, heapIndex, 1);
      +
      16551  if(heapBudget.usage + size * allocationCount > heapBudget.budget)
      +
      16552  {
      +
      16553  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      +
      16554  }
      16555  }
      -
      16556  if((createInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 &&
      -
      16557  (createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
      -
      16558  {
      -
      16559  VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT together with VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT makes no sense.");
      -
      16560  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      -
      16561  }
      -
      16562  if((createInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 &&
      - +
      16556 
      +
      16557  VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
      +
      16558  allocInfo.memoryTypeIndex = memTypeIndex;
      +
      16559  allocInfo.allocationSize = size;
      +
      16560 
      +
      16561 #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
      +
      16562  VkMemoryDedicatedAllocateInfoKHR dedicatedAllocInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR };
      +
      16563  if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
      16564  {
      -
      16565  VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_MAPPED_BIT together with VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT is invalid.");
      -
      16566  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      -
      16567  }
      -
      16568  if(requiresDedicatedAllocation)
      -
      16569  {
      -
      16570  if((createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
      -
      16571  {
      -
      16572  VMA_ASSERT(0 && "VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT specified while dedicated allocation is required.");
      -
      16573  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      -
      16574  }
      -
      16575  if(createInfo.pool != VK_NULL_HANDLE)
      -
      16576  {
      -
      16577  VMA_ASSERT(0 && "Pool specified while dedicated allocation is required.");
      -
      16578  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      -
      16579  }
      -
      16580  }
      -
      16581  if((createInfo.pool != VK_NULL_HANDLE) &&
      -
      16582  ((createInfo.flags & (VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT)) != 0))
      -
      16583  {
      -
      16584  VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT when pool != null is invalid.");
      -
      16585  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      -
      16586  }
      -
      16587 
      -
      16588  if(createInfo.pool != VK_NULL_HANDLE)
      -
      16589  {
      -
      16590  const VkDeviceSize alignmentForPool = VMA_MAX(
      -
      16591  vkMemReq.alignment,
      -
      16592  GetMemoryTypeMinAlignment(createInfo.pool->m_BlockVector.GetMemoryTypeIndex()));
      -
      16593 
      -
      16594  VmaAllocationCreateInfo createInfoForPool = createInfo;
      -
      16595  // If memory type is not HOST_VISIBLE, disable MAPPED.
      -
      16596  if((createInfoForPool.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 &&
      -
      16597  (m_MemProps.memoryTypes[createInfo.pool->m_BlockVector.GetMemoryTypeIndex()].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
      -
      16598  {
      -
      16599  createInfoForPool.flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT;
      -
      16600  }
      -
      16601 
      -
      16602  return createInfo.pool->m_BlockVector.Allocate(
      -
      16603  m_CurrentFrameIndex.load(),
      -
      16604  vkMemReq.size,
      -
      16605  alignmentForPool,
      -
      16606  createInfoForPool,
      -
      16607  suballocType,
      -
      16608  allocationCount,
      -
      16609  pAllocations);
      -
      16610  }
      -
      16611  else
      -
      16612  {
      -
      16613  // Bit mask of memory Vulkan types acceptable for this allocation.
      -
      16614  uint32_t memoryTypeBits = vkMemReq.memoryTypeBits;
      -
      16615  uint32_t memTypeIndex = UINT32_MAX;
      -
      16616  VkResult res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &createInfo, &memTypeIndex);
      -
      16617  if(res == VK_SUCCESS)
      -
      16618  {
      -
      16619  VkDeviceSize alignmentForMemType = VMA_MAX(
      -
      16620  vkMemReq.alignment,
      -
      16621  GetMemoryTypeMinAlignment(memTypeIndex));
      -
      16622 
      -
      16623  res = AllocateMemoryOfType(
      -
      16624  vkMemReq.size,
      -
      16625  alignmentForMemType,
      -
      16626  requiresDedicatedAllocation || prefersDedicatedAllocation,
      -
      16627  dedicatedBuffer,
      -
      16628  dedicatedBufferUsage,
      -
      16629  dedicatedImage,
      -
      16630  createInfo,
      -
      16631  memTypeIndex,
      -
      16632  suballocType,
      -
      16633  allocationCount,
      -
      16634  pAllocations);
      -
      16635  // Succeeded on first try.
      -
      16636  if(res == VK_SUCCESS)
      -
      16637  {
      -
      16638  return res;
      -
      16639  }
      -
      16640  // Allocation from this memory type failed. Try other compatible memory types.
      -
      16641  else
      -
      16642  {
      -
      16643  for(;;)
      -
      16644  {
      -
      16645  // Remove old memTypeIndex from list of possibilities.
      -
      16646  memoryTypeBits &= ~(1u << memTypeIndex);
      -
      16647  // Find alternative memTypeIndex.
      -
      16648  res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &createInfo, &memTypeIndex);
      -
      16649  if(res == VK_SUCCESS)
      -
      16650  {
      -
      16651  alignmentForMemType = VMA_MAX(
      -
      16652  vkMemReq.alignment,
      -
      16653  GetMemoryTypeMinAlignment(memTypeIndex));
      -
      16654 
      -
      16655  res = AllocateMemoryOfType(
      -
      16656  vkMemReq.size,
      -
      16657  alignmentForMemType,
      -
      16658  requiresDedicatedAllocation || prefersDedicatedAllocation,
      -
      16659  dedicatedBuffer,
      -
      16660  dedicatedBufferUsage,
      -
      16661  dedicatedImage,
      -
      16662  createInfo,
      -
      16663  memTypeIndex,
      -
      16664  suballocType,
      -
      16665  allocationCount,
      -
      16666  pAllocations);
      -
      16667  // Allocation from this alternative memory type succeeded.
      -
      16668  if(res == VK_SUCCESS)
      -
      16669  {
      -
      16670  return res;
      -
      16671  }
      -
      16672  // else: Allocation from this memory type failed. Try next one - next loop iteration.
      -
      16673  }
      -
      16674  // No other matching memory type index could be found.
      -
      16675  else
      -
      16676  {
      -
      16677  // Not returning res, which is VK_ERROR_FEATURE_NOT_PRESENT, because we already failed to allocate once.
      -
      16678  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      -
      16679  }
      -
      16680  }
      -
      16681  }
      -
      16682  }
      -
      16683  // Can't find any single memory type maching requirements. res is VK_ERROR_FEATURE_NOT_PRESENT.
      -
      16684  else
      -
      16685  return res;
      -
      16686  }
      -
      16687 }
      -
      16688 
      -
      16689 void VmaAllocator_T::FreeMemory(
      -
      16690  size_t allocationCount,
      -
      16691  const VmaAllocation* pAllocations)
      -
      16692 {
      -
      16693  VMA_ASSERT(pAllocations);
      -
      16694 
      -
      16695  for(size_t allocIndex = allocationCount; allocIndex--; )
      -
      16696  {
      -
      16697  VmaAllocation allocation = pAllocations[allocIndex];
      -
      16698 
      -
      16699  if(allocation != VK_NULL_HANDLE)
      -
      16700  {
      -
      16701  if(TouchAllocation(allocation))
      -
      16702  {
      -
      16703  if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
      -
      16704  {
      -
      16705  FillAllocation(allocation, VMA_ALLOCATION_FILL_PATTERN_DESTROYED);
      -
      16706  }
      -
      16707 
      -
      16708  switch(allocation->GetType())
      -
      16709  {
      -
      16710  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
      -
      16711  {
      -
      16712  VmaBlockVector* pBlockVector = VMA_NULL;
      -
      16713  VmaPool hPool = allocation->GetBlock()->GetParentPool();
      -
      16714  if(hPool != VK_NULL_HANDLE)
      -
      16715  {
      -
      16716  pBlockVector = &hPool->m_BlockVector;
      -
      16717  }
      -
      16718  else
      -
      16719  {
      -
      16720  const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex();
      -
      16721  pBlockVector = m_pBlockVectors[memTypeIndex];
      -
      16722  }
      -
      16723  pBlockVector->Free(allocation);
      -
      16724  }
      -
      16725  break;
      -
      16726  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
      -
      16727  FreeDedicatedMemory(allocation);
      -
      16728  break;
      -
      16729  default:
      -
      16730  VMA_ASSERT(0);
      -
      16731  }
      -
      16732  }
      -
      16733 
      -
      16734  // Do this regardless of whether the allocation is lost. Lost allocations still account to Budget.AllocationBytes.
      -
      16735  m_Budget.RemoveAllocation(MemoryTypeIndexToHeapIndex(allocation->GetMemoryTypeIndex()), allocation->GetSize());
      -
      16736  allocation->SetUserData(this, VMA_NULL);
      -
      16737  m_AllocationObjectAllocator.Free(allocation);
      -
      16738  }
      -
      16739  }
      -
      16740 }
      -
      16741 
      -
      16742 VkResult VmaAllocator_T::ResizeAllocation(
      -
      16743  const VmaAllocation alloc,
      -
      16744  VkDeviceSize newSize)
      -
      16745 {
      -
      16746  // This function is deprecated and so it does nothing. It's left for backward compatibility.
      -
      16747  if(newSize == 0 || alloc->GetLastUseFrameIndex() == VMA_FRAME_INDEX_LOST)
      -
      16748  {
      -
      16749  return VK_ERROR_VALIDATION_FAILED_EXT;
      +
      16565  if(dedicatedBuffer != VK_NULL_HANDLE)
      +
      16566  {
      +
      16567  VMA_ASSERT(dedicatedImage == VK_NULL_HANDLE);
      +
      16568  dedicatedAllocInfo.buffer = dedicatedBuffer;
      +
      16569  VmaPnextChainPushFront(&allocInfo, &dedicatedAllocInfo);
      +
      16570  }
      +
      16571  else if(dedicatedImage != VK_NULL_HANDLE)
      +
      16572  {
      +
      16573  dedicatedAllocInfo.image = dedicatedImage;
      +
      16574  VmaPnextChainPushFront(&allocInfo, &dedicatedAllocInfo);
      +
      16575  }
      +
      16576  }
      +
      16577 #endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
      +
      16578 
      +
      16579 #if VMA_BUFFER_DEVICE_ADDRESS
      +
      16580  VkMemoryAllocateFlagsInfoKHR allocFlagsInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR };
      +
      16581  if(m_UseKhrBufferDeviceAddress)
      +
      16582  {
      +
      16583  bool canContainBufferWithDeviceAddress = true;
      +
      16584  if(dedicatedBuffer != VK_NULL_HANDLE)
      +
      16585  {
      +
      16586  canContainBufferWithDeviceAddress = dedicatedBufferUsage == UINT32_MAX || // Usage flags unknown
      +
      16587  (dedicatedBufferUsage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT) != 0;
      +
      16588  }
      +
      16589  else if(dedicatedImage != VK_NULL_HANDLE)
      +
      16590  {
      +
      16591  canContainBufferWithDeviceAddress = false;
      +
      16592  }
      +
      16593  if(canContainBufferWithDeviceAddress)
      +
      16594  {
      +
      16595  allocFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
      +
      16596  VmaPnextChainPushFront(&allocInfo, &allocFlagsInfo);
      +
      16597  }
      +
      16598  }
      +
      16599 #endif // #if VMA_BUFFER_DEVICE_ADDRESS
      +
      16600 
      +
      16601 #if VMA_MEMORY_PRIORITY
      +
      16602  VkMemoryPriorityAllocateInfoEXT priorityInfo = { VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT };
      +
      16603  if(m_UseExtMemoryPriority)
      +
      16604  {
      +
      16605  priorityInfo.priority = priority;
      +
      16606  VmaPnextChainPushFront(&allocInfo, &priorityInfo);
      +
      16607  }
      +
      16608 #endif // #if VMA_MEMORY_PRIORITY
      +
      16609 
      +
      16610  size_t allocIndex;
      +
      16611  VkResult res = VK_SUCCESS;
      +
      16612  for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
      +
      16613  {
      +
      16614  res = AllocateDedicatedMemoryPage(
      +
      16615  size,
      +
      16616  suballocType,
      +
      16617  memTypeIndex,
      +
      16618  allocInfo,
      +
      16619  map,
      +
      16620  isUserDataString,
      +
      16621  pUserData,
      +
      16622  pAllocations + allocIndex);
      +
      16623  if(res != VK_SUCCESS)
      +
      16624  {
      +
      16625  break;
      +
      16626  }
      +
      16627  }
      +
      16628 
      +
      16629  if(res == VK_SUCCESS)
      +
      16630  {
      +
      16631  // Register them in m_DedicatedAllocations.
      +
      16632  {
      +
      16633  VmaMutexLockWrite lock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
      +
      16634  DedicatedAllocationLinkedList& dedicatedAllocations = m_DedicatedAllocations[memTypeIndex];
      +
      16635  for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
      +
      16636  {
      +
      16637  dedicatedAllocations.PushBack(pAllocations[allocIndex]);
      +
      16638  }
      +
      16639  }
      +
      16640 
      +
      16641  VMA_DEBUG_LOG(" Allocated DedicatedMemory Count=%zu, MemoryTypeIndex=#%u", allocationCount, memTypeIndex);
      +
      16642  }
      +
      16643  else
      +
      16644  {
      +
      16645  // Free all already created allocations.
      +
      16646  while(allocIndex--)
      +
      16647  {
      +
      16648  VmaAllocation currAlloc = pAllocations[allocIndex];
      +
      16649  VkDeviceMemory hMemory = currAlloc->GetMemory();
      +
      16650 
      +
      16651  /*
      +
      16652  There is no need to call this, because Vulkan spec allows to skip vkUnmapMemory
      +
      16653  before vkFreeMemory.
      +
      16654 
      +
      16655  if(currAlloc->GetMappedData() != VMA_NULL)
      +
      16656  {
      +
      16657  (*m_VulkanFunctions.vkUnmapMemory)(m_hDevice, hMemory);
      +
      16658  }
      +
      16659  */
      +
      16660 
      +
      16661  FreeVulkanMemory(memTypeIndex, currAlloc->GetSize(), hMemory);
      +
      16662  m_Budget.RemoveAllocation(MemoryTypeIndexToHeapIndex(memTypeIndex), currAlloc->GetSize());
      +
      16663  currAlloc->SetUserData(this, VMA_NULL);
      +
      16664  m_AllocationObjectAllocator.Free(currAlloc);
      +
      16665  }
      +
      16666 
      +
      16667  memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount);
      +
      16668  }
      +
      16669 
      +
      16670  return res;
      +
      16671 }
      +
      16672 
      +
      16673 VkResult VmaAllocator_T::AllocateDedicatedMemoryPage(
      +
      16674  VkDeviceSize size,
      +
      16675  VmaSuballocationType suballocType,
      +
      16676  uint32_t memTypeIndex,
      +
      16677  const VkMemoryAllocateInfo& allocInfo,
      +
      16678  bool map,
      +
      16679  bool isUserDataString,
      +
      16680  void* pUserData,
      +
      16681  VmaAllocation* pAllocation)
      +
      16682 {
      +
      16683  VkDeviceMemory hMemory = VK_NULL_HANDLE;
      +
      16684  VkResult res = AllocateVulkanMemory(&allocInfo, &hMemory);
      +
      16685  if(res < 0)
      +
      16686  {
      +
      16687  VMA_DEBUG_LOG(" vkAllocateMemory FAILED");
      +
      16688  return res;
      +
      16689  }
      +
      16690 
      +
      16691  void* pMappedData = VMA_NULL;
      +
      16692  if(map)
      +
      16693  {
      +
      16694  res = (*m_VulkanFunctions.vkMapMemory)(
      +
      16695  m_hDevice,
      +
      16696  hMemory,
      +
      16697  0,
      +
      16698  VK_WHOLE_SIZE,
      +
      16699  0,
      +
      16700  &pMappedData);
      +
      16701  if(res < 0)
      +
      16702  {
      +
      16703  VMA_DEBUG_LOG(" vkMapMemory FAILED");
      +
      16704  FreeVulkanMemory(memTypeIndex, size, hMemory);
      +
      16705  return res;
      +
      16706  }
      +
      16707  }
      +
      16708 
      +
      16709  *pAllocation = m_AllocationObjectAllocator.Allocate(m_CurrentFrameIndex.load(), isUserDataString);
      +
      16710  (*pAllocation)->InitDedicatedAllocation(memTypeIndex, hMemory, suballocType, pMappedData, size);
      +
      16711  (*pAllocation)->SetUserData(this, pUserData);
      +
      16712  m_Budget.AddAllocation(MemoryTypeIndexToHeapIndex(memTypeIndex), size);
      +
      16713  if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
      +
      16714  {
      +
      16715  FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED);
      +
      16716  }
      +
      16717 
      +
      16718  return VK_SUCCESS;
      +
      16719 }
      +
      16720 
      +
      16721 void VmaAllocator_T::GetBufferMemoryRequirements(
      +
      16722  VkBuffer hBuffer,
      +
      16723  VkMemoryRequirements& memReq,
      +
      16724  bool& requiresDedicatedAllocation,
      +
      16725  bool& prefersDedicatedAllocation) const
      +
      16726 {
      +
      16727 #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
      +
      16728  if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
      +
      16729  {
      +
      16730  VkBufferMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR };
      +
      16731  memReqInfo.buffer = hBuffer;
      +
      16732 
      +
      16733  VkMemoryDedicatedRequirementsKHR memDedicatedReq = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR };
      +
      16734 
      +
      16735  VkMemoryRequirements2KHR memReq2 = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR };
      +
      16736  VmaPnextChainPushFront(&memReq2, &memDedicatedReq);
      +
      16737 
      +
      16738  (*m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR)(m_hDevice, &memReqInfo, &memReq2);
      +
      16739 
      +
      16740  memReq = memReq2.memoryRequirements;
      +
      16741  requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE);
      +
      16742  prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE);
      +
      16743  }
      +
      16744  else
      +
      16745 #endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
      +
      16746  {
      +
      16747  (*m_VulkanFunctions.vkGetBufferMemoryRequirements)(m_hDevice, hBuffer, &memReq);
      +
      16748  requiresDedicatedAllocation = false;
      +
      16749  prefersDedicatedAllocation = false;
      16750  }
      -
      16751  if(newSize == alloc->GetSize())
      -
      16752  {
      -
      16753  return VK_SUCCESS;
      -
      16754  }
      -
      16755  return VK_ERROR_OUT_OF_POOL_MEMORY;
      -
      16756 }
      -
      16757 
      -
      16758 void VmaAllocator_T::CalculateStats(VmaStats* pStats)
      -
      16759 {
      -
      16760  // Initialize.
      -
      16761  InitStatInfo(pStats->total);
      -
      16762  for(size_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i)
      -
      16763  InitStatInfo(pStats->memoryType[i]);
      -
      16764  for(size_t i = 0; i < VK_MAX_MEMORY_HEAPS; ++i)
      -
      16765  InitStatInfo(pStats->memoryHeap[i]);
      +
      16751 }
      +
      16752 
      +
      16753 void VmaAllocator_T::GetImageMemoryRequirements(
      +
      16754  VkImage hImage,
      +
      16755  VkMemoryRequirements& memReq,
      +
      16756  bool& requiresDedicatedAllocation,
      +
      16757  bool& prefersDedicatedAllocation) const
      +
      16758 {
      +
      16759 #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
      +
      16760  if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0))
      +
      16761  {
      +
      16762  VkImageMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR };
      +
      16763  memReqInfo.image = hImage;
      +
      16764 
      +
      16765  VkMemoryDedicatedRequirementsKHR memDedicatedReq = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR };
      16766 
      -
      16767  // Process default pools.
      -
      16768  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
      -
      16769  {
      -
      16770  VmaBlockVector* const pBlockVector = m_pBlockVectors[memTypeIndex];
      -
      16771  VMA_ASSERT(pBlockVector);
      -
      16772  pBlockVector->AddStats(pStats);
      -
      16773  }
      -
      16774 
      -
      16775  // Process custom pools.
      -
      16776  {
      -
      16777  VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex);
      -
      16778  for(size_t poolIndex = 0, poolCount = m_Pools.size(); poolIndex < poolCount; ++poolIndex)
      -
      16779  {
      -
      16780  m_Pools[poolIndex]->m_BlockVector.AddStats(pStats);
      -
      16781  }
      +
      16767  VkMemoryRequirements2KHR memReq2 = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR };
      +
      16768  VmaPnextChainPushFront(&memReq2, &memDedicatedReq);
      +
      16769 
      +
      16770  (*m_VulkanFunctions.vkGetImageMemoryRequirements2KHR)(m_hDevice, &memReqInfo, &memReq2);
      +
      16771 
      +
      16772  memReq = memReq2.memoryRequirements;
      +
      16773  requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE);
      +
      16774  prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE);
      +
      16775  }
      +
      16776  else
      +
      16777 #endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
      +
      16778  {
      +
      16779  (*m_VulkanFunctions.vkGetImageMemoryRequirements)(m_hDevice, hImage, &memReq);
      +
      16780  requiresDedicatedAllocation = false;
      +
      16781  prefersDedicatedAllocation = false;
      16782  }
      -
      16783 
      -
      16784  // Process dedicated allocations.
      -
      16785  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
      -
      16786  {
      -
      16787  const uint32_t memHeapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
      -
      16788  VmaMutexLockRead dedicatedAllocationsLock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
      -
      16789  AllocationVectorType* const pDedicatedAllocVector = m_pDedicatedAllocations[memTypeIndex];
      -
      16790  VMA_ASSERT(pDedicatedAllocVector);
      -
      16791  for(size_t allocIndex = 0, allocCount = pDedicatedAllocVector->size(); allocIndex < allocCount; ++allocIndex)
      -
      16792  {
      -
      16793  VmaStatInfo allocationStatInfo;
      -
      16794  (*pDedicatedAllocVector)[allocIndex]->DedicatedAllocCalcStatsInfo(allocationStatInfo);
      -
      16795  VmaAddStatInfo(pStats->total, allocationStatInfo);
      -
      16796  VmaAddStatInfo(pStats->memoryType[memTypeIndex], allocationStatInfo);
      -
      16797  VmaAddStatInfo(pStats->memoryHeap[memHeapIndex], allocationStatInfo);
      -
      16798  }
      -
      16799  }
      +
      16783 }
      +
      16784 
      +
      16785 VkResult VmaAllocator_T::AllocateMemory(
      +
      16786  const VkMemoryRequirements& vkMemReq,
      +
      16787  bool requiresDedicatedAllocation,
      +
      16788  bool prefersDedicatedAllocation,
      +
      16789  VkBuffer dedicatedBuffer,
      +
      16790  VkBufferUsageFlags dedicatedBufferUsage,
      +
      16791  VkImage dedicatedImage,
      +
      16792  const VmaAllocationCreateInfo& createInfo,
      +
      16793  VmaSuballocationType suballocType,
      +
      16794  size_t allocationCount,
      +
      16795  VmaAllocation* pAllocations)
      +
      16796 {
      +
      16797  memset(pAllocations, 0, sizeof(VmaAllocation) * allocationCount);
      +
      16798 
      +
      16799  VMA_ASSERT(VmaIsPow2(vkMemReq.alignment));
      16800 
      -
      16801  // Postprocess.
      -
      16802  VmaPostprocessCalcStatInfo(pStats->total);
      -
      16803  for(size_t i = 0; i < GetMemoryTypeCount(); ++i)
      -
      16804  VmaPostprocessCalcStatInfo(pStats->memoryType[i]);
      -
      16805  for(size_t i = 0; i < GetMemoryHeapCount(); ++i)
      -
      16806  VmaPostprocessCalcStatInfo(pStats->memoryHeap[i]);
      -
      16807 }
      -
      16808 
      -
      16809 void VmaAllocator_T::GetBudget(VmaBudget* outBudget, uint32_t firstHeap, uint32_t heapCount)
      -
      16810 {
      -
      16811 #if VMA_MEMORY_BUDGET
      -
      16812  if(m_UseExtMemoryBudget)
      +
      16801  if(vkMemReq.size == 0)
      +
      16802  {
      +
      16803  return VK_ERROR_VALIDATION_FAILED_EXT;
      +
      16804  }
      +
      16805  if((createInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 &&
      +
      16806  (createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
      +
      16807  {
      +
      16808  VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT together with VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT makes no sense.");
      +
      16809  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      +
      16810  }
      +
      16811  if((createInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 &&
      +
      16813  {
      -
      16814  if(m_Budget.m_OperationsSinceBudgetFetch < 30)
      -
      16815  {
      -
      16816  VmaMutexLockRead lockRead(m_Budget.m_BudgetMutex, m_UseMutex);
      -
      16817  for(uint32_t i = 0; i < heapCount; ++i, ++outBudget)
      -
      16818  {
      -
      16819  const uint32_t heapIndex = firstHeap + i;
      -
      16820 
      -
      16821  outBudget->blockBytes = m_Budget.m_BlockBytes[heapIndex];
      -
      16822  outBudget->allocationBytes = m_Budget.m_AllocationBytes[heapIndex];
      -
      16823 
      -
      16824  if(m_Budget.m_VulkanUsage[heapIndex] + outBudget->blockBytes > m_Budget.m_BlockBytesAtBudgetFetch[heapIndex])
      -
      16825  {
      -
      16826  outBudget->usage = m_Budget.m_VulkanUsage[heapIndex] +
      -
      16827  outBudget->blockBytes - m_Budget.m_BlockBytesAtBudgetFetch[heapIndex];
      -
      16828  }
      -
      16829  else
      -
      16830  {
      -
      16831  outBudget->usage = 0;
      -
      16832  }
      -
      16833 
      -
      16834  // Have to take MIN with heap size because explicit HeapSizeLimit is included in it.
      -
      16835  outBudget->budget = VMA_MIN(
      -
      16836  m_Budget.m_VulkanBudget[heapIndex], m_MemProps.memoryHeaps[heapIndex].size);
      -
      16837  }
      -
      16838  }
      -
      16839  else
      -
      16840  {
      -
      16841  UpdateVulkanBudget(); // Outside of mutex lock
      -
      16842  GetBudget(outBudget, firstHeap, heapCount); // Recursion
      -
      16843  }
      -
      16844  }
      -
      16845  else
      -
      16846 #endif
      -
      16847  {
      -
      16848  for(uint32_t i = 0; i < heapCount; ++i, ++outBudget)
      -
      16849  {
      -
      16850  const uint32_t heapIndex = firstHeap + i;
      -
      16851 
      -
      16852  outBudget->blockBytes = m_Budget.m_BlockBytes[heapIndex];
      -
      16853  outBudget->allocationBytes = m_Budget.m_AllocationBytes[heapIndex];
      -
      16854 
      -
      16855  outBudget->usage = outBudget->blockBytes;
      -
      16856  outBudget->budget = m_MemProps.memoryHeaps[heapIndex].size * 8 / 10; // 80% heuristics.
      -
      16857  }
      -
      16858  }
      -
      16859 }
      -
      16860 
      -
      16861 static const uint32_t VMA_VENDOR_ID_AMD = 4098;
      -
      16862 
      -
      16863 VkResult VmaAllocator_T::DefragmentationBegin(
      -
      16864  const VmaDefragmentationInfo2& info,
      -
      16865  VmaDefragmentationStats* pStats,
      -
      16866  VmaDefragmentationContext* pContext)
      -
      16867 {
      -
      16868  if(info.pAllocationsChanged != VMA_NULL)
      -
      16869  {
      -
      16870  memset(info.pAllocationsChanged, 0, info.allocationCount * sizeof(VkBool32));
      -
      16871  }
      -
      16872 
      -
      16873  *pContext = vma_new(this, VmaDefragmentationContext_T)(
      -
      16874  this, m_CurrentFrameIndex.load(), info.flags, pStats);
      -
      16875 
      -
      16876  (*pContext)->AddPools(info.poolCount, info.pPools);
      -
      16877  (*pContext)->AddAllocations(
      - -
      16879 
      -
      16880  VkResult res = (*pContext)->Defragment(
      - - -
      16883  info.commandBuffer, pStats, info.flags);
      -
      16884 
      -
      16885  if(res != VK_NOT_READY)
      -
      16886  {
      -
      16887  vma_delete(this, *pContext);
      -
      16888  *pContext = VMA_NULL;
      -
      16889  }
      -
      16890 
      -
      16891  return res;
      -
      16892 }
      -
      16893 
      -
      16894 VkResult VmaAllocator_T::DefragmentationEnd(
      -
      16895  VmaDefragmentationContext context)
      -
      16896 {
      -
      16897  vma_delete(this, context);
      -
      16898  return VK_SUCCESS;
      -
      16899 }
      -
      16900 
      -
      16901 VkResult VmaAllocator_T::DefragmentationPassBegin(
      - -
      16903  VmaDefragmentationContext context)
      -
      16904 {
      -
      16905  return context->DefragmentPassBegin(pInfo);
      -
      16906 }
      -
      16907 VkResult VmaAllocator_T::DefragmentationPassEnd(
      -
      16908  VmaDefragmentationContext context)
      -
      16909 {
      -
      16910  return context->DefragmentPassEnd();
      -
      16911 
      -
      16912 }
      -
      16913 
      -
      16914 void VmaAllocator_T::GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo)
      -
      16915 {
      -
      16916  if(hAllocation->CanBecomeLost())
      -
      16917  {
      -
      16918  /*
      -
      16919  Warning: This is a carefully designed algorithm.
      -
      16920  Do not modify unless you really know what you're doing :)
      -
      16921  */
      -
      16922  const uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load();
      -
      16923  uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex();
      -
      16924  for(;;)
      -
      16925  {
      -
      16926  if(localLastUseFrameIndex == VMA_FRAME_INDEX_LOST)
      -
      16927  {
      -
      16928  pAllocationInfo->memoryType = UINT32_MAX;
      -
      16929  pAllocationInfo->deviceMemory = VK_NULL_HANDLE;
      -
      16930  pAllocationInfo->offset = 0;
      -
      16931  pAllocationInfo->size = hAllocation->GetSize();
      -
      16932  pAllocationInfo->pMappedData = VMA_NULL;
      -
      16933  pAllocationInfo->pUserData = hAllocation->GetUserData();
      -
      16934  return;
      -
      16935  }
      -
      16936  else if(localLastUseFrameIndex == localCurrFrameIndex)
      -
      16937  {
      -
      16938  pAllocationInfo->memoryType = hAllocation->GetMemoryTypeIndex();
      -
      16939  pAllocationInfo->deviceMemory = hAllocation->GetMemory();
      -
      16940  pAllocationInfo->offset = hAllocation->GetOffset();
      -
      16941  pAllocationInfo->size = hAllocation->GetSize();
      -
      16942  pAllocationInfo->pMappedData = VMA_NULL;
      -
      16943  pAllocationInfo->pUserData = hAllocation->GetUserData();
      -
      16944  return;
      -
      16945  }
      -
      16946  else // Last use time earlier than current time.
      -
      16947  {
      -
      16948  if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex))
      -
      16949  {
      -
      16950  localLastUseFrameIndex = localCurrFrameIndex;
      -
      16951  }
      -
      16952  }
      -
      16953  }
      -
      16954  }
      -
      16955  else
      -
      16956  {
      -
      16957 #if VMA_STATS_STRING_ENABLED
      -
      16958  uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load();
      -
      16959  uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex();
      -
      16960  for(;;)
      -
      16961  {
      -
      16962  VMA_ASSERT(localLastUseFrameIndex != VMA_FRAME_INDEX_LOST);
      -
      16963  if(localLastUseFrameIndex == localCurrFrameIndex)
      -
      16964  {
      -
      16965  break;
      -
      16966  }
      -
      16967  else // Last use time earlier than current time.
      -
      16968  {
      -
      16969  if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex))
      -
      16970  {
      -
      16971  localLastUseFrameIndex = localCurrFrameIndex;
      -
      16972  }
      -
      16973  }
      -
      16974  }
      -
      16975 #endif
      -
      16976 
      -
      16977  pAllocationInfo->memoryType = hAllocation->GetMemoryTypeIndex();
      -
      16978  pAllocationInfo->deviceMemory = hAllocation->GetMemory();
      -
      16979  pAllocationInfo->offset = hAllocation->GetOffset();
      -
      16980  pAllocationInfo->size = hAllocation->GetSize();
      -
      16981  pAllocationInfo->pMappedData = hAllocation->GetMappedData();
      -
      16982  pAllocationInfo->pUserData = hAllocation->GetUserData();
      -
      16983  }
      -
      16984 }
      -
      16985 
      -
      16986 bool VmaAllocator_T::TouchAllocation(VmaAllocation hAllocation)
      -
      16987 {
      -
      16988  // This is a stripped-down version of VmaAllocator_T::GetAllocationInfo.
      -
      16989  if(hAllocation->CanBecomeLost())
      -
      16990  {
      -
      16991  uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load();
      -
      16992  uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex();
      -
      16993  for(;;)
      -
      16994  {
      -
      16995  if(localLastUseFrameIndex == VMA_FRAME_INDEX_LOST)
      -
      16996  {
      -
      16997  return false;
      -
      16998  }
      -
      16999  else if(localLastUseFrameIndex == localCurrFrameIndex)
      -
      17000  {
      -
      17001  return true;
      -
      17002  }
      -
      17003  else // Last use time earlier than current time.
      -
      17004  {
      -
      17005  if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex))
      -
      17006  {
      -
      17007  localLastUseFrameIndex = localCurrFrameIndex;
      -
      17008  }
      -
      17009  }
      -
      17010  }
      -
      17011  }
      -
      17012  else
      -
      17013  {
      -
      17014 #if VMA_STATS_STRING_ENABLED
      -
      17015  uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load();
      -
      17016  uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex();
      -
      17017  for(;;)
      -
      17018  {
      -
      17019  VMA_ASSERT(localLastUseFrameIndex != VMA_FRAME_INDEX_LOST);
      -
      17020  if(localLastUseFrameIndex == localCurrFrameIndex)
      -
      17021  {
      -
      17022  break;
      -
      17023  }
      -
      17024  else // Last use time earlier than current time.
      -
      17025  {
      -
      17026  if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex))
      -
      17027  {
      -
      17028  localLastUseFrameIndex = localCurrFrameIndex;
      -
      17029  }
      -
      17030  }
      +
      16814  VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_MAPPED_BIT together with VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT is invalid.");
      +
      16815  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      +
      16816  }
      +
      16817  if(requiresDedicatedAllocation)
      +
      16818  {
      +
      16819  if((createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
      +
      16820  {
      +
      16821  VMA_ASSERT(0 && "VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT specified while dedicated allocation is required.");
      +
      16822  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      +
      16823  }
      +
      16824  if(createInfo.pool != VK_NULL_HANDLE)
      +
      16825  {
      +
      16826  VMA_ASSERT(0 && "Pool specified while dedicated allocation is required.");
      +
      16827  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      +
      16828  }
      +
      16829  }
      +
      16830  if((createInfo.pool != VK_NULL_HANDLE) &&
      +
      16831  ((createInfo.flags & (VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT)) != 0))
      +
      16832  {
      +
      16833  VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT when pool != null is invalid.");
      +
      16834  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      +
      16835  }
      +
      16836 
      +
      16837  if(createInfo.pool != VK_NULL_HANDLE)
      +
      16838  {
      +
      16839  const VkDeviceSize alignmentForPool = VMA_MAX(
      +
      16840  vkMemReq.alignment,
      +
      16841  GetMemoryTypeMinAlignment(createInfo.pool->m_BlockVector.GetMemoryTypeIndex()));
      +
      16842 
      +
      16843  VmaAllocationCreateInfo createInfoForPool = createInfo;
      +
      16844  // If memory type is not HOST_VISIBLE, disable MAPPED.
      +
      16845  if((createInfoForPool.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 &&
      +
      16846  (m_MemProps.memoryTypes[createInfo.pool->m_BlockVector.GetMemoryTypeIndex()].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
      +
      16847  {
      +
      16848  createInfoForPool.flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT;
      +
      16849  }
      +
      16850 
      +
      16851  return createInfo.pool->m_BlockVector.Allocate(
      +
      16852  m_CurrentFrameIndex.load(),
      +
      16853  vkMemReq.size,
      +
      16854  alignmentForPool,
      +
      16855  createInfoForPool,
      +
      16856  suballocType,
      +
      16857  allocationCount,
      +
      16858  pAllocations);
      +
      16859  }
      +
      16860  else
      +
      16861  {
      +
      16862  // Bit mask of memory Vulkan types acceptable for this allocation.
      +
      16863  uint32_t memoryTypeBits = vkMemReq.memoryTypeBits;
      +
      16864  uint32_t memTypeIndex = UINT32_MAX;
      +
      16865  VkResult res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &createInfo, &memTypeIndex);
      +
      16866  if(res == VK_SUCCESS)
      +
      16867  {
      +
      16868  VkDeviceSize alignmentForMemType = VMA_MAX(
      +
      16869  vkMemReq.alignment,
      +
      16870  GetMemoryTypeMinAlignment(memTypeIndex));
      +
      16871 
      +
      16872  res = AllocateMemoryOfType(
      +
      16873  vkMemReq.size,
      +
      16874  alignmentForMemType,
      +
      16875  requiresDedicatedAllocation || prefersDedicatedAllocation,
      +
      16876  dedicatedBuffer,
      +
      16877  dedicatedBufferUsage,
      +
      16878  dedicatedImage,
      +
      16879  createInfo,
      +
      16880  memTypeIndex,
      +
      16881  suballocType,
      +
      16882  allocationCount,
      +
      16883  pAllocations);
      +
      16884  // Succeeded on first try.
      +
      16885  if(res == VK_SUCCESS)
      +
      16886  {
      +
      16887  return res;
      +
      16888  }
      +
      16889  // Allocation from this memory type failed. Try other compatible memory types.
      +
      16890  else
      +
      16891  {
      +
      16892  for(;;)
      +
      16893  {
      +
      16894  // Remove old memTypeIndex from list of possibilities.
      +
      16895  memoryTypeBits &= ~(1u << memTypeIndex);
      +
      16896  // Find alternative memTypeIndex.
      +
      16897  res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &createInfo, &memTypeIndex);
      +
      16898  if(res == VK_SUCCESS)
      +
      16899  {
      +
      16900  alignmentForMemType = VMA_MAX(
      +
      16901  vkMemReq.alignment,
      +
      16902  GetMemoryTypeMinAlignment(memTypeIndex));
      +
      16903 
      +
      16904  res = AllocateMemoryOfType(
      +
      16905  vkMemReq.size,
      +
      16906  alignmentForMemType,
      +
      16907  requiresDedicatedAllocation || prefersDedicatedAllocation,
      +
      16908  dedicatedBuffer,
      +
      16909  dedicatedBufferUsage,
      +
      16910  dedicatedImage,
      +
      16911  createInfo,
      +
      16912  memTypeIndex,
      +
      16913  suballocType,
      +
      16914  allocationCount,
      +
      16915  pAllocations);
      +
      16916  // Allocation from this alternative memory type succeeded.
      +
      16917  if(res == VK_SUCCESS)
      +
      16918  {
      +
      16919  return res;
      +
      16920  }
      +
      16921  // else: Allocation from this memory type failed. Try next one - next loop iteration.
      +
      16922  }
      +
      16923  // No other matching memory type index could be found.
      +
      16924  else
      +
      16925  {
      +
      16926  // Not returning res, which is VK_ERROR_FEATURE_NOT_PRESENT, because we already failed to allocate once.
      +
      16927  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      +
      16928  }
      +
      16929  }
      +
      16930  }
      +
      16931  }
      +
      16932  // Can't find any single memory type maching requirements. res is VK_ERROR_FEATURE_NOT_PRESENT.
      +
      16933  else
      +
      16934  return res;
      +
      16935  }
      +
      16936 }
      +
      16937 
      +
      16938 void VmaAllocator_T::FreeMemory(
      +
      16939  size_t allocationCount,
      +
      16940  const VmaAllocation* pAllocations)
      +
      16941 {
      +
      16942  VMA_ASSERT(pAllocations);
      +
      16943 
      +
      16944  for(size_t allocIndex = allocationCount; allocIndex--; )
      +
      16945  {
      +
      16946  VmaAllocation allocation = pAllocations[allocIndex];
      +
      16947 
      +
      16948  if(allocation != VK_NULL_HANDLE)
      +
      16949  {
      +
      16950  if(TouchAllocation(allocation))
      +
      16951  {
      +
      16952  if(VMA_DEBUG_INITIALIZE_ALLOCATIONS)
      +
      16953  {
      +
      16954  FillAllocation(allocation, VMA_ALLOCATION_FILL_PATTERN_DESTROYED);
      +
      16955  }
      +
      16956 
      +
      16957  switch(allocation->GetType())
      +
      16958  {
      +
      16959  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
      +
      16960  {
      +
      16961  VmaBlockVector* pBlockVector = VMA_NULL;
      +
      16962  VmaPool hPool = allocation->GetBlock()->GetParentPool();
      +
      16963  if(hPool != VK_NULL_HANDLE)
      +
      16964  {
      +
      16965  pBlockVector = &hPool->m_BlockVector;
      +
      16966  }
      +
      16967  else
      +
      16968  {
      +
      16969  const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex();
      +
      16970  pBlockVector = m_pBlockVectors[memTypeIndex];
      +
      16971  }
      +
      16972  pBlockVector->Free(allocation);
      +
      16973  }
      +
      16974  break;
      +
      16975  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
      +
      16976  FreeDedicatedMemory(allocation);
      +
      16977  break;
      +
      16978  default:
      +
      16979  VMA_ASSERT(0);
      +
      16980  }
      +
      16981  }
      +
      16982 
      +
      16983  // Do this regardless of whether the allocation is lost. Lost allocations still account to Budget.AllocationBytes.
      +
      16984  m_Budget.RemoveAllocation(MemoryTypeIndexToHeapIndex(allocation->GetMemoryTypeIndex()), allocation->GetSize());
      +
      16985  allocation->SetUserData(this, VMA_NULL);
      +
      16986  m_AllocationObjectAllocator.Free(allocation);
      +
      16987  }
      +
      16988  }
      +
      16989 }
      +
      16990 
      +
      16991 void VmaAllocator_T::CalculateStats(VmaStats* pStats)
      +
      16992 {
      +
      16993  // Initialize.
      +
      16994  InitStatInfo(pStats->total);
      +
      16995  for(size_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i)
      +
      16996  InitStatInfo(pStats->memoryType[i]);
      +
      16997  for(size_t i = 0; i < VK_MAX_MEMORY_HEAPS; ++i)
      +
      16998  InitStatInfo(pStats->memoryHeap[i]);
      +
      16999 
      +
      17000  // Process default pools.
      +
      17001  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
      +
      17002  {
      +
      17003  VmaBlockVector* const pBlockVector = m_pBlockVectors[memTypeIndex];
      +
      17004  VMA_ASSERT(pBlockVector);
      +
      17005  pBlockVector->AddStats(pStats);
      +
      17006  }
      +
      17007 
      +
      17008  // Process custom pools.
      +
      17009  {
      +
      17010  VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex);
      +
      17011  for(VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool))
      +
      17012  {
      +
      17013  pool->m_BlockVector.AddStats(pStats);
      +
      17014  }
      +
      17015  }
      +
      17016 
      +
      17017  // Process dedicated allocations.
      +
      17018  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
      +
      17019  {
      +
      17020  const uint32_t memHeapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
      +
      17021  VmaMutexLockRead dedicatedAllocationsLock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
      +
      17022  DedicatedAllocationLinkedList& dedicatedAllocList = m_DedicatedAllocations[memTypeIndex];
      +
      17023  for(VmaAllocation alloc = dedicatedAllocList.Front();
      +
      17024  alloc != VMA_NULL; alloc = dedicatedAllocList.GetNext(alloc))
      +
      17025  {
      +
      17026  VmaStatInfo allocationStatInfo;
      +
      17027  alloc->DedicatedAllocCalcStatsInfo(allocationStatInfo);
      +
      17028  VmaAddStatInfo(pStats->total, allocationStatInfo);
      +
      17029  VmaAddStatInfo(pStats->memoryType[memTypeIndex], allocationStatInfo);
      +
      17030  VmaAddStatInfo(pStats->memoryHeap[memHeapIndex], allocationStatInfo);
      17031  }
      -
      17032 #endif
      +
      17032  }
      17033 
      -
      17034  return true;
      -
      17035  }
      -
      17036 }
      -
      17037 
      -
      17038 VkResult VmaAllocator_T::CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPool* pPool)
      -
      17039 {
      -
      17040  VMA_DEBUG_LOG(" CreatePool: MemoryTypeIndex=%u, flags=%u", pCreateInfo->memoryTypeIndex, pCreateInfo->flags);
      +
      17034  // Postprocess.
      +
      17035  VmaPostprocessCalcStatInfo(pStats->total);
      +
      17036  for(size_t i = 0; i < GetMemoryTypeCount(); ++i)
      +
      17037  VmaPostprocessCalcStatInfo(pStats->memoryType[i]);
      +
      17038  for(size_t i = 0; i < GetMemoryHeapCount(); ++i)
      +
      17039  VmaPostprocessCalcStatInfo(pStats->memoryHeap[i]);
      +
      17040 }
      17041 
      -
      17042  VmaPoolCreateInfo newCreateInfo = *pCreateInfo;
      -
      17043 
      -
      17044  if(newCreateInfo.maxBlockCount == 0)
      -
      17045  {
      -
      17046  newCreateInfo.maxBlockCount = SIZE_MAX;
      -
      17047  }
      -
      17048  if(newCreateInfo.minBlockCount > newCreateInfo.maxBlockCount)
      -
      17049  {
      -
      17050  return VK_ERROR_INITIALIZATION_FAILED;
      -
      17051  }
      -
      17052  // Memory type index out of range or forbidden.
      -
      17053  if(pCreateInfo->memoryTypeIndex >= GetMemoryTypeCount() ||
      -
      17054  ((1u << pCreateInfo->memoryTypeIndex) & m_GlobalMemoryTypeBits) == 0)
      -
      17055  {
      -
      17056  return VK_ERROR_FEATURE_NOT_PRESENT;
      -
      17057  }
      -
      17058 
      -
      17059  const VkDeviceSize preferredBlockSize = CalcPreferredBlockSize(newCreateInfo.memoryTypeIndex);
      -
      17060 
      -
      17061  *pPool = vma_new(this, VmaPool_T)(this, newCreateInfo, preferredBlockSize);
      -
      17062 
      -
      17063  VkResult res = (*pPool)->m_BlockVector.CreateMinBlocks();
      -
      17064  if(res != VK_SUCCESS)
      -
      17065  {
      -
      17066  vma_delete(this, *pPool);
      -
      17067  *pPool = VMA_NULL;
      -
      17068  return res;
      -
      17069  }
      -
      17070 
      -
      17071  // Add to m_Pools.
      -
      17072  {
      -
      17073  VmaMutexLockWrite lock(m_PoolsMutex, m_UseMutex);
      -
      17074  (*pPool)->SetId(m_NextPoolId++);
      -
      17075  VmaVectorInsertSorted<VmaPointerLess>(m_Pools, *pPool);
      -
      17076  }
      -
      17077 
      -
      17078  return VK_SUCCESS;
      -
      17079 }
      -
      17080 
      -
      17081 void VmaAllocator_T::DestroyPool(VmaPool pool)
      -
      17082 {
      -
      17083  // Remove from m_Pools.
      -
      17084  {
      -
      17085  VmaMutexLockWrite lock(m_PoolsMutex, m_UseMutex);
      -
      17086  bool success = VmaVectorRemoveSorted<VmaPointerLess>(m_Pools, pool);
      -
      17087  VMA_ASSERT(success && "Pool not found in Allocator.");
      -
      17088  }
      -
      17089 
      -
      17090  vma_delete(this, pool);
      -
      17091 }
      -
      17092 
      -
      17093 void VmaAllocator_T::GetPoolStats(VmaPool pool, VmaPoolStats* pPoolStats)
      -
      17094 {
      -
      17095  pool->m_BlockVector.GetPoolStats(pPoolStats);
      -
      17096 }
      -
      17097 
      -
      17098 void VmaAllocator_T::SetCurrentFrameIndex(uint32_t frameIndex)
      -
      17099 {
      -
      17100  m_CurrentFrameIndex.store(frameIndex);
      -
      17101 
      -
      17102 #if VMA_MEMORY_BUDGET
      -
      17103  if(m_UseExtMemoryBudget)
      -
      17104  {
      -
      17105  UpdateVulkanBudget();
      -
      17106  }
      -
      17107 #endif // #if VMA_MEMORY_BUDGET
      -
      17108 }
      -
      17109 
      -
      17110 void VmaAllocator_T::MakePoolAllocationsLost(
      -
      17111  VmaPool hPool,
      -
      17112  size_t* pLostAllocationCount)
      -
      17113 {
      -
      17114  hPool->m_BlockVector.MakePoolAllocationsLost(
      -
      17115  m_CurrentFrameIndex.load(),
      -
      17116  pLostAllocationCount);
      -
      17117 }
      -
      17118 
      -
      17119 VkResult VmaAllocator_T::CheckPoolCorruption(VmaPool hPool)
      -
      17120 {
      -
      17121  return hPool->m_BlockVector.CheckCorruption();
      -
      17122 }
      +
      17042 void VmaAllocator_T::GetBudget(VmaBudget* outBudget, uint32_t firstHeap, uint32_t heapCount)
      +
      17043 {
      +
      17044 #if VMA_MEMORY_BUDGET
      +
      17045  if(m_UseExtMemoryBudget)
      +
      17046  {
      +
      17047  if(m_Budget.m_OperationsSinceBudgetFetch < 30)
      +
      17048  {
      +
      17049  VmaMutexLockRead lockRead(m_Budget.m_BudgetMutex, m_UseMutex);
      +
      17050  for(uint32_t i = 0; i < heapCount; ++i, ++outBudget)
      +
      17051  {
      +
      17052  const uint32_t heapIndex = firstHeap + i;
      +
      17053 
      +
      17054  outBudget->blockBytes = m_Budget.m_BlockBytes[heapIndex];
      +
      17055  outBudget->allocationBytes = m_Budget.m_AllocationBytes[heapIndex];
      +
      17056 
      +
      17057  if(m_Budget.m_VulkanUsage[heapIndex] + outBudget->blockBytes > m_Budget.m_BlockBytesAtBudgetFetch[heapIndex])
      +
      17058  {
      +
      17059  outBudget->usage = m_Budget.m_VulkanUsage[heapIndex] +
      +
      17060  outBudget->blockBytes - m_Budget.m_BlockBytesAtBudgetFetch[heapIndex];
      +
      17061  }
      +
      17062  else
      +
      17063  {
      +
      17064  outBudget->usage = 0;
      +
      17065  }
      +
      17066 
      +
      17067  // Have to take MIN with heap size because explicit HeapSizeLimit is included in it.
      +
      17068  outBudget->budget = VMA_MIN(
      +
      17069  m_Budget.m_VulkanBudget[heapIndex], m_MemProps.memoryHeaps[heapIndex].size);
      +
      17070  }
      +
      17071  }
      +
      17072  else
      +
      17073  {
      +
      17074  UpdateVulkanBudget(); // Outside of mutex lock
      +
      17075  GetBudget(outBudget, firstHeap, heapCount); // Recursion
      +
      17076  }
      +
      17077  }
      +
      17078  else
      +
      17079 #endif
      +
      17080  {
      +
      17081  for(uint32_t i = 0; i < heapCount; ++i, ++outBudget)
      +
      17082  {
      +
      17083  const uint32_t heapIndex = firstHeap + i;
      +
      17084 
      +
      17085  outBudget->blockBytes = m_Budget.m_BlockBytes[heapIndex];
      +
      17086  outBudget->allocationBytes = m_Budget.m_AllocationBytes[heapIndex];
      +
      17087 
      +
      17088  outBudget->usage = outBudget->blockBytes;
      +
      17089  outBudget->budget = m_MemProps.memoryHeaps[heapIndex].size * 8 / 10; // 80% heuristics.
      +
      17090  }
      +
      17091  }
      +
      17092 }
      +
      17093 
      +
      17094 static const uint32_t VMA_VENDOR_ID_AMD = 4098;
      +
      17095 
      +
      17096 VkResult VmaAllocator_T::DefragmentationBegin(
      +
      17097  const VmaDefragmentationInfo2& info,
      +
      17098  VmaDefragmentationStats* pStats,
      +
      17099  VmaDefragmentationContext* pContext)
      +
      17100 {
      +
      17101  if(info.pAllocationsChanged != VMA_NULL)
      +
      17102  {
      +
      17103  memset(info.pAllocationsChanged, 0, info.allocationCount * sizeof(VkBool32));
      +
      17104  }
      +
      17105 
      +
      17106  *pContext = vma_new(this, VmaDefragmentationContext_T)(
      +
      17107  this, m_CurrentFrameIndex.load(), info.flags, pStats);
      +
      17108 
      +
      17109  (*pContext)->AddPools(info.poolCount, info.pPools);
      +
      17110  (*pContext)->AddAllocations(
      + +
      17112 
      +
      17113  VkResult res = (*pContext)->Defragment(
      + + +
      17116  info.commandBuffer, pStats, info.flags);
      +
      17117 
      +
      17118  if(res != VK_NOT_READY)
      +
      17119  {
      +
      17120  vma_delete(this, *pContext);
      +
      17121  *pContext = VMA_NULL;
      +
      17122  }
      17123 
      -
      17124 VkResult VmaAllocator_T::CheckCorruption(uint32_t memoryTypeBits)
      -
      17125 {
      -
      17126  VkResult finalRes = VK_ERROR_FEATURE_NOT_PRESENT;
      -
      17127 
      -
      17128  // Process default pools.
      -
      17129  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
      -
      17130  {
      -
      17131  if(((1u << memTypeIndex) & memoryTypeBits) != 0)
      -
      17132  {
      -
      17133  VmaBlockVector* const pBlockVector = m_pBlockVectors[memTypeIndex];
      -
      17134  VMA_ASSERT(pBlockVector);
      -
      17135  VkResult localRes = pBlockVector->CheckCorruption();
      -
      17136  switch(localRes)
      -
      17137  {
      -
      17138  case VK_ERROR_FEATURE_NOT_PRESENT:
      -
      17139  break;
      -
      17140  case VK_SUCCESS:
      -
      17141  finalRes = VK_SUCCESS;
      -
      17142  break;
      -
      17143  default:
      -
      17144  return localRes;
      -
      17145  }
      -
      17146  }
      -
      17147  }
      -
      17148 
      -
      17149  // Process custom pools.
      +
      17124  return res;
      +
      17125 }
      +
      17126 
      +
      17127 VkResult VmaAllocator_T::DefragmentationEnd(
      +
      17128  VmaDefragmentationContext context)
      +
      17129 {
      +
      17130  vma_delete(this, context);
      +
      17131  return VK_SUCCESS;
      +
      17132 }
      +
      17133 
      +
      17134 VkResult VmaAllocator_T::DefragmentationPassBegin(
      + +
      17136  VmaDefragmentationContext context)
      +
      17137 {
      +
      17138  return context->DefragmentPassBegin(pInfo);
      +
      17139 }
      +
      17140 VkResult VmaAllocator_T::DefragmentationPassEnd(
      +
      17141  VmaDefragmentationContext context)
      +
      17142 {
      +
      17143  return context->DefragmentPassEnd();
      +
      17144 
      +
      17145 }
      +
      17146 
      +
      17147 void VmaAllocator_T::GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo)
      +
      17148 {
      +
      17149  if(hAllocation->CanBecomeLost())
      17150  {
      -
      17151  VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex);
      -
      17152  for(size_t poolIndex = 0, poolCount = m_Pools.size(); poolIndex < poolCount; ++poolIndex)
      -
      17153  {
      -
      17154  if(((1u << m_Pools[poolIndex]->m_BlockVector.GetMemoryTypeIndex()) & memoryTypeBits) != 0)
      -
      17155  {
      -
      17156  VkResult localRes = m_Pools[poolIndex]->m_BlockVector.CheckCorruption();
      -
      17157  switch(localRes)
      -
      17158  {
      -
      17159  case VK_ERROR_FEATURE_NOT_PRESENT:
      -
      17160  break;
      -
      17161  case VK_SUCCESS:
      -
      17162  finalRes = VK_SUCCESS;
      -
      17163  break;
      -
      17164  default:
      -
      17165  return localRes;
      -
      17166  }
      -
      17167  }
      -
      17168  }
      -
      17169  }
      -
      17170 
      -
      17171  return finalRes;
      -
      17172 }
      -
      17173 
      -
      17174 void VmaAllocator_T::CreateLostAllocation(VmaAllocation* pAllocation)
      -
      17175 {
      -
      17176  *pAllocation = m_AllocationObjectAllocator.Allocate(VMA_FRAME_INDEX_LOST, false);
      -
      17177  (*pAllocation)->InitLost();
      -
      17178 }
      -
      17179 
      -
      17180 VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory)
      -
      17181 {
      -
      17182  const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(pAllocateInfo->memoryTypeIndex);
      -
      17183 
      -
      17184  // HeapSizeLimit is in effect for this heap.
      -
      17185  if((m_HeapSizeLimitMask & (1u << heapIndex)) != 0)
      -
      17186  {
      -
      17187  const VkDeviceSize heapSize = m_MemProps.memoryHeaps[heapIndex].size;
      -
      17188  VkDeviceSize blockBytes = m_Budget.m_BlockBytes[heapIndex];
      -
      17189  for(;;)
      -
      17190  {
      -
      17191  const VkDeviceSize blockBytesAfterAllocation = blockBytes + pAllocateInfo->allocationSize;
      -
      17192  if(blockBytesAfterAllocation > heapSize)
      -
      17193  {
      -
      17194  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      -
      17195  }
      -
      17196  if(m_Budget.m_BlockBytes[heapIndex].compare_exchange_strong(blockBytes, blockBytesAfterAllocation))
      +
      17151  /*
      +
      17152  Warning: This is a carefully designed algorithm.
      +
      17153  Do not modify unless you really know what you're doing :)
      +
      17154  */
      +
      17155  const uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load();
      +
      17156  uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex();
      +
      17157  for(;;)
      +
      17158  {
      +
      17159  if(localLastUseFrameIndex == VMA_FRAME_INDEX_LOST)
      +
      17160  {
      +
      17161  pAllocationInfo->memoryType = UINT32_MAX;
      +
      17162  pAllocationInfo->deviceMemory = VK_NULL_HANDLE;
      +
      17163  pAllocationInfo->offset = 0;
      +
      17164  pAllocationInfo->size = hAllocation->GetSize();
      +
      17165  pAllocationInfo->pMappedData = VMA_NULL;
      +
      17166  pAllocationInfo->pUserData = hAllocation->GetUserData();
      +
      17167  return;
      +
      17168  }
      +
      17169  else if(localLastUseFrameIndex == localCurrFrameIndex)
      +
      17170  {
      +
      17171  pAllocationInfo->memoryType = hAllocation->GetMemoryTypeIndex();
      +
      17172  pAllocationInfo->deviceMemory = hAllocation->GetMemory();
      +
      17173  pAllocationInfo->offset = hAllocation->GetOffset();
      +
      17174  pAllocationInfo->size = hAllocation->GetSize();
      +
      17175  pAllocationInfo->pMappedData = VMA_NULL;
      +
      17176  pAllocationInfo->pUserData = hAllocation->GetUserData();
      +
      17177  return;
      +
      17178  }
      +
      17179  else // Last use time earlier than current time.
      +
      17180  {
      +
      17181  if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex))
      +
      17182  {
      +
      17183  localLastUseFrameIndex = localCurrFrameIndex;
      +
      17184  }
      +
      17185  }
      +
      17186  }
      +
      17187  }
      +
      17188  else
      +
      17189  {
      +
      17190 #if VMA_STATS_STRING_ENABLED
      +
      17191  uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load();
      +
      17192  uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex();
      +
      17193  for(;;)
      +
      17194  {
      +
      17195  VMA_ASSERT(localLastUseFrameIndex != VMA_FRAME_INDEX_LOST);
      +
      17196  if(localLastUseFrameIndex == localCurrFrameIndex)
      17197  {
      17198  break;
      17199  }
      -
      17200  }
      -
      17201  }
      -
      17202  else
      -
      17203  {
      -
      17204  m_Budget.m_BlockBytes[heapIndex] += pAllocateInfo->allocationSize;
      -
      17205  }
      -
      17206 
      -
      17207  // VULKAN CALL vkAllocateMemory.
      -
      17208  VkResult res = (*m_VulkanFunctions.vkAllocateMemory)(m_hDevice, pAllocateInfo, GetAllocationCallbacks(), pMemory);
      +
      17200  else // Last use time earlier than current time.
      +
      17201  {
      +
      17202  if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex))
      +
      17203  {
      +
      17204  localLastUseFrameIndex = localCurrFrameIndex;
      +
      17205  }
      +
      17206  }
      +
      17207  }
      +
      17208 #endif
      17209 
      -
      17210  if(res == VK_SUCCESS)
      -
      17211  {
      -
      17212 #if VMA_MEMORY_BUDGET
      -
      17213  ++m_Budget.m_OperationsSinceBudgetFetch;
      -
      17214 #endif
      -
      17215 
      -
      17216  // Informative callback.
      -
      17217  if(m_DeviceMemoryCallbacks.pfnAllocate != VMA_NULL)
      -
      17218  {
      -
      17219  (*m_DeviceMemoryCallbacks.pfnAllocate)(this, pAllocateInfo->memoryTypeIndex, *pMemory, pAllocateInfo->allocationSize, m_DeviceMemoryCallbacks.pUserData);
      -
      17220  }
      -
      17221  }
      -
      17222  else
      +
      17210  pAllocationInfo->memoryType = hAllocation->GetMemoryTypeIndex();
      +
      17211  pAllocationInfo->deviceMemory = hAllocation->GetMemory();
      +
      17212  pAllocationInfo->offset = hAllocation->GetOffset();
      +
      17213  pAllocationInfo->size = hAllocation->GetSize();
      +
      17214  pAllocationInfo->pMappedData = hAllocation->GetMappedData();
      +
      17215  pAllocationInfo->pUserData = hAllocation->GetUserData();
      +
      17216  }
      +
      17217 }
      +
      17218 
      +
      17219 bool VmaAllocator_T::TouchAllocation(VmaAllocation hAllocation)
      +
      17220 {
      +
      17221  // This is a stripped-down version of VmaAllocator_T::GetAllocationInfo.
      +
      17222  if(hAllocation->CanBecomeLost())
      17223  {
      -
      17224  m_Budget.m_BlockBytes[heapIndex] -= pAllocateInfo->allocationSize;
      -
      17225  }
      -
      17226 
      -
      17227  return res;
      -
      17228 }
      -
      17229 
      -
      17230 void VmaAllocator_T::FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, VkDeviceMemory hMemory)
      -
      17231 {
      -
      17232  // Informative callback.
      -
      17233  if(m_DeviceMemoryCallbacks.pfnFree != VMA_NULL)
      -
      17234  {
      -
      17235  (*m_DeviceMemoryCallbacks.pfnFree)(this, memoryType, hMemory, size, m_DeviceMemoryCallbacks.pUserData);
      -
      17236  }
      -
      17237 
      -
      17238  // VULKAN CALL vkFreeMemory.
      -
      17239  (*m_VulkanFunctions.vkFreeMemory)(m_hDevice, hMemory, GetAllocationCallbacks());
      -
      17240 
      -
      17241  m_Budget.m_BlockBytes[MemoryTypeIndexToHeapIndex(memoryType)] -= size;
      -
      17242 }
      -
      17243 
      -
      17244 VkResult VmaAllocator_T::BindVulkanBuffer(
      -
      17245  VkDeviceMemory memory,
      -
      17246  VkDeviceSize memoryOffset,
      -
      17247  VkBuffer buffer,
      -
      17248  const void* pNext)
      -
      17249 {
      -
      17250  if(pNext != VMA_NULL)
      -
      17251  {
      -
      17252 #if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2
      -
      17253  if((m_UseKhrBindMemory2 || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) &&
      -
      17254  m_VulkanFunctions.vkBindBufferMemory2KHR != VMA_NULL)
      -
      17255  {
      -
      17256  VkBindBufferMemoryInfoKHR bindBufferMemoryInfo = { VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR };
      -
      17257  bindBufferMemoryInfo.pNext = pNext;
      -
      17258  bindBufferMemoryInfo.buffer = buffer;
      -
      17259  bindBufferMemoryInfo.memory = memory;
      -
      17260  bindBufferMemoryInfo.memoryOffset = memoryOffset;
      -
      17261  return (*m_VulkanFunctions.vkBindBufferMemory2KHR)(m_hDevice, 1, &bindBufferMemoryInfo);
      -
      17262  }
      -
      17263  else
      -
      17264 #endif // #if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2
      -
      17265  {
      -
      17266  return VK_ERROR_EXTENSION_NOT_PRESENT;
      -
      17267  }
      +
      17224  uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load();
      +
      17225  uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex();
      +
      17226  for(;;)
      +
      17227  {
      +
      17228  if(localLastUseFrameIndex == VMA_FRAME_INDEX_LOST)
      +
      17229  {
      +
      17230  return false;
      +
      17231  }
      +
      17232  else if(localLastUseFrameIndex == localCurrFrameIndex)
      +
      17233  {
      +
      17234  return true;
      +
      17235  }
      +
      17236  else // Last use time earlier than current time.
      +
      17237  {
      +
      17238  if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex))
      +
      17239  {
      +
      17240  localLastUseFrameIndex = localCurrFrameIndex;
      +
      17241  }
      +
      17242  }
      +
      17243  }
      +
      17244  }
      +
      17245  else
      +
      17246  {
      +
      17247 #if VMA_STATS_STRING_ENABLED
      +
      17248  uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load();
      +
      17249  uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex();
      +
      17250  for(;;)
      +
      17251  {
      +
      17252  VMA_ASSERT(localLastUseFrameIndex != VMA_FRAME_INDEX_LOST);
      +
      17253  if(localLastUseFrameIndex == localCurrFrameIndex)
      +
      17254  {
      +
      17255  break;
      +
      17256  }
      +
      17257  else // Last use time earlier than current time.
      +
      17258  {
      +
      17259  if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex))
      +
      17260  {
      +
      17261  localLastUseFrameIndex = localCurrFrameIndex;
      +
      17262  }
      +
      17263  }
      +
      17264  }
      +
      17265 #endif
      +
      17266 
      +
      17267  return true;
      17268  }
      -
      17269  else
      -
      17270  {
      -
      17271  return (*m_VulkanFunctions.vkBindBufferMemory)(m_hDevice, buffer, memory, memoryOffset);
      -
      17272  }
      -
      17273 }
      +
      17269 }
      +
      17270 
      +
      17271 VkResult VmaAllocator_T::CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPool* pPool)
      +
      17272 {
      +
      17273  VMA_DEBUG_LOG(" CreatePool: MemoryTypeIndex=%u, flags=%u", pCreateInfo->memoryTypeIndex, pCreateInfo->flags);
      17274 
      -
      17275 VkResult VmaAllocator_T::BindVulkanImage(
      -
      17276  VkDeviceMemory memory,
      -
      17277  VkDeviceSize memoryOffset,
      -
      17278  VkImage image,
      -
      17279  const void* pNext)
      -
      17280 {
      -
      17281  if(pNext != VMA_NULL)
      +
      17275  VmaPoolCreateInfo newCreateInfo = *pCreateInfo;
      +
      17276 
      +
      17277  if(newCreateInfo.maxBlockCount == 0)
      +
      17278  {
      +
      17279  newCreateInfo.maxBlockCount = SIZE_MAX;
      +
      17280  }
      +
      17281  if(newCreateInfo.minBlockCount > newCreateInfo.maxBlockCount)
      17282  {
      -
      17283 #if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2
      -
      17284  if((m_UseKhrBindMemory2 || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) &&
      -
      17285  m_VulkanFunctions.vkBindImageMemory2KHR != VMA_NULL)
      -
      17286  {
      -
      17287  VkBindImageMemoryInfoKHR bindBufferMemoryInfo = { VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR };
      -
      17288  bindBufferMemoryInfo.pNext = pNext;
      -
      17289  bindBufferMemoryInfo.image = image;
      -
      17290  bindBufferMemoryInfo.memory = memory;
      -
      17291  bindBufferMemoryInfo.memoryOffset = memoryOffset;
      -
      17292  return (*m_VulkanFunctions.vkBindImageMemory2KHR)(m_hDevice, 1, &bindBufferMemoryInfo);
      -
      17293  }
      -
      17294  else
      -
      17295 #endif // #if VMA_BIND_MEMORY2
      -
      17296  {
      -
      17297  return VK_ERROR_EXTENSION_NOT_PRESENT;
      -
      17298  }
      -
      17299  }
      -
      17300  else
      -
      17301  {
      -
      17302  return (*m_VulkanFunctions.vkBindImageMemory)(m_hDevice, image, memory, memoryOffset);
      -
      17303  }
      -
      17304 }
      -
      17305 
      -
      17306 VkResult VmaAllocator_T::Map(VmaAllocation hAllocation, void** ppData)
      -
      17307 {
      -
      17308  if(hAllocation->CanBecomeLost())
      -
      17309  {
      -
      17310  return VK_ERROR_MEMORY_MAP_FAILED;
      -
      17311  }
      -
      17312 
      -
      17313  switch(hAllocation->GetType())
      -
      17314  {
      -
      17315  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
      -
      17316  {
      -
      17317  VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock();
      -
      17318  char *pBytes = VMA_NULL;
      -
      17319  VkResult res = pBlock->Map(this, 1, (void**)&pBytes);
      -
      17320  if(res == VK_SUCCESS)
      -
      17321  {
      -
      17322  *ppData = pBytes + (ptrdiff_t)hAllocation->GetOffset();
      -
      17323  hAllocation->BlockAllocMap();
      -
      17324  }
      -
      17325  return res;
      -
      17326  }
      -
      17327  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
      -
      17328  return hAllocation->DedicatedAllocMap(this, ppData);
      -
      17329  default:
      -
      17330  VMA_ASSERT(0);
      -
      17331  return VK_ERROR_MEMORY_MAP_FAILED;
      -
      17332  }
      -
      17333 }
      -
      17334 
      -
      17335 void VmaAllocator_T::Unmap(VmaAllocation hAllocation)
      -
      17336 {
      -
      17337  switch(hAllocation->GetType())
      -
      17338  {
      -
      17339  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
      -
      17340  {
      -
      17341  VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock();
      -
      17342  hAllocation->BlockAllocUnmap();
      -
      17343  pBlock->Unmap(this, 1);
      -
      17344  }
      -
      17345  break;
      -
      17346  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
      -
      17347  hAllocation->DedicatedAllocUnmap(this);
      -
      17348  break;
      -
      17349  default:
      -
      17350  VMA_ASSERT(0);
      -
      17351  }
      -
      17352 }
      -
      17353 
      -
      17354 VkResult VmaAllocator_T::BindBufferMemory(
      -
      17355  VmaAllocation hAllocation,
      -
      17356  VkDeviceSize allocationLocalOffset,
      -
      17357  VkBuffer hBuffer,
      -
      17358  const void* pNext)
      -
      17359 {
      -
      17360  VkResult res = VK_SUCCESS;
      -
      17361  switch(hAllocation->GetType())
      +
      17283  return VK_ERROR_INITIALIZATION_FAILED;
      +
      17284  }
      +
      17285  // Memory type index out of range or forbidden.
      +
      17286  if(pCreateInfo->memoryTypeIndex >= GetMemoryTypeCount() ||
      +
      17287  ((1u << pCreateInfo->memoryTypeIndex) & m_GlobalMemoryTypeBits) == 0)
      +
      17288  {
      +
      17289  return VK_ERROR_FEATURE_NOT_PRESENT;
      +
      17290  }
      +
      17291 
      +
      17292  const VkDeviceSize preferredBlockSize = CalcPreferredBlockSize(newCreateInfo.memoryTypeIndex);
      +
      17293 
      +
      17294  *pPool = vma_new(this, VmaPool_T)(this, newCreateInfo, preferredBlockSize);
      +
      17295 
      +
      17296  VkResult res = (*pPool)->m_BlockVector.CreateMinBlocks();
      +
      17297  if(res != VK_SUCCESS)
      +
      17298  {
      +
      17299  vma_delete(this, *pPool);
      +
      17300  *pPool = VMA_NULL;
      +
      17301  return res;
      +
      17302  }
      +
      17303 
      +
      17304  // Add to m_Pools.
      +
      17305  {
      +
      17306  VmaMutexLockWrite lock(m_PoolsMutex, m_UseMutex);
      +
      17307  (*pPool)->SetId(m_NextPoolId++);
      +
      17308  m_Pools.PushBack(*pPool);
      +
      17309  }
      +
      17310 
      +
      17311  return VK_SUCCESS;
      +
      17312 }
      +
      17313 
      +
      17314 void VmaAllocator_T::DestroyPool(VmaPool pool)
      +
      17315 {
      +
      17316  // Remove from m_Pools.
      +
      17317  {
      +
      17318  VmaMutexLockWrite lock(m_PoolsMutex, m_UseMutex);
      +
      17319  m_Pools.Remove(pool);
      +
      17320  }
      +
      17321 
      +
      17322  vma_delete(this, pool);
      +
      17323 }
      +
      17324 
      +
      17325 void VmaAllocator_T::GetPoolStats(VmaPool pool, VmaPoolStats* pPoolStats)
      +
      17326 {
      +
      17327  pool->m_BlockVector.GetPoolStats(pPoolStats);
      +
      17328 }
      +
      17329 
      +
      17330 void VmaAllocator_T::SetCurrentFrameIndex(uint32_t frameIndex)
      +
      17331 {
      +
      17332  m_CurrentFrameIndex.store(frameIndex);
      +
      17333 
      +
      17334 #if VMA_MEMORY_BUDGET
      +
      17335  if(m_UseExtMemoryBudget)
      +
      17336  {
      +
      17337  UpdateVulkanBudget();
      +
      17338  }
      +
      17339 #endif // #if VMA_MEMORY_BUDGET
      +
      17340 }
      +
      17341 
      +
      17342 void VmaAllocator_T::MakePoolAllocationsLost(
      +
      17343  VmaPool hPool,
      +
      17344  size_t* pLostAllocationCount)
      +
      17345 {
      +
      17346  hPool->m_BlockVector.MakePoolAllocationsLost(
      +
      17347  m_CurrentFrameIndex.load(),
      +
      17348  pLostAllocationCount);
      +
      17349 }
      +
      17350 
      +
      17351 VkResult VmaAllocator_T::CheckPoolCorruption(VmaPool hPool)
      +
      17352 {
      +
      17353  return hPool->m_BlockVector.CheckCorruption();
      +
      17354 }
      +
      17355 
      +
      17356 VkResult VmaAllocator_T::CheckCorruption(uint32_t memoryTypeBits)
      +
      17357 {
      +
      17358  VkResult finalRes = VK_ERROR_FEATURE_NOT_PRESENT;
      +
      17359 
      +
      17360  // Process default pools.
      +
      17361  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
      17362  {
      -
      17363  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
      -
      17364  res = BindVulkanBuffer(hAllocation->GetMemory(), allocationLocalOffset, hBuffer, pNext);
      -
      17365  break;
      -
      17366  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
      -
      17367  {
      -
      17368  VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock();
      -
      17369  VMA_ASSERT(pBlock && "Binding buffer to allocation that doesn't belong to any block. Is the allocation lost?");
      -
      17370  res = pBlock->BindBufferMemory(this, hAllocation, allocationLocalOffset, hBuffer, pNext);
      -
      17371  break;
      -
      17372  }
      -
      17373  default:
      -
      17374  VMA_ASSERT(0);
      -
      17375  }
      -
      17376  return res;
      -
      17377 }
      -
      17378 
      -
      17379 VkResult VmaAllocator_T::BindImageMemory(
      -
      17380  VmaAllocation hAllocation,
      -
      17381  VkDeviceSize allocationLocalOffset,
      -
      17382  VkImage hImage,
      -
      17383  const void* pNext)
      -
      17384 {
      -
      17385  VkResult res = VK_SUCCESS;
      -
      17386  switch(hAllocation->GetType())
      -
      17387  {
      -
      17388  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
      -
      17389  res = BindVulkanImage(hAllocation->GetMemory(), allocationLocalOffset, hImage, pNext);
      -
      17390  break;
      -
      17391  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
      -
      17392  {
      -
      17393  VmaDeviceMemoryBlock* pBlock = hAllocation->GetBlock();
      -
      17394  VMA_ASSERT(pBlock && "Binding image to allocation that doesn't belong to any block. Is the allocation lost?");
      -
      17395  res = pBlock->BindImageMemory(this, hAllocation, allocationLocalOffset, hImage, pNext);
      -
      17396  break;
      -
      17397  }
      -
      17398  default:
      -
      17399  VMA_ASSERT(0);
      -
      17400  }
      -
      17401  return res;
      -
      17402 }
      -
      17403 
      -
      17404 VkResult VmaAllocator_T::FlushOrInvalidateAllocation(
      -
      17405  VmaAllocation hAllocation,
      -
      17406  VkDeviceSize offset, VkDeviceSize size,
      -
      17407  VMA_CACHE_OPERATION op)
      -
      17408 {
      -
      17409  VkResult res = VK_SUCCESS;
      -
      17410 
      -
      17411  VkMappedMemoryRange memRange = {};
      -
      17412  if(GetFlushOrInvalidateRange(hAllocation, offset, size, memRange))
      -
      17413  {
      -
      17414  switch(op)
      -
      17415  {
      -
      17416  case VMA_CACHE_FLUSH:
      -
      17417  res = (*GetVulkanFunctions().vkFlushMappedMemoryRanges)(m_hDevice, 1, &memRange);
      -
      17418  break;
      -
      17419  case VMA_CACHE_INVALIDATE:
      -
      17420  res = (*GetVulkanFunctions().vkInvalidateMappedMemoryRanges)(m_hDevice, 1, &memRange);
      -
      17421  break;
      -
      17422  default:
      -
      17423  VMA_ASSERT(0);
      -
      17424  }
      -
      17425  }
      -
      17426  // else: Just ignore this call.
      -
      17427  return res;
      -
      17428 }
      -
      17429 
      -
      17430 VkResult VmaAllocator_T::FlushOrInvalidateAllocations(
      -
      17431  uint32_t allocationCount,
      -
      17432  const VmaAllocation* allocations,
      -
      17433  const VkDeviceSize* offsets, const VkDeviceSize* sizes,
      -
      17434  VMA_CACHE_OPERATION op)
      -
      17435 {
      -
      17436  typedef VmaStlAllocator<VkMappedMemoryRange> RangeAllocator;
      -
      17437  typedef VmaSmallVector<VkMappedMemoryRange, RangeAllocator, 16> RangeVector;
      -
      17438  RangeVector ranges = RangeVector(RangeAllocator(GetAllocationCallbacks()));
      -
      17439 
      -
      17440  for(uint32_t allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
      -
      17441  {
      -
      17442  const VmaAllocation alloc = allocations[allocIndex];
      -
      17443  const VkDeviceSize offset = offsets != VMA_NULL ? offsets[allocIndex] : 0;
      -
      17444  const VkDeviceSize size = sizes != VMA_NULL ? sizes[allocIndex] : VK_WHOLE_SIZE;
      -
      17445  VkMappedMemoryRange newRange;
      -
      17446  if(GetFlushOrInvalidateRange(alloc, offset, size, newRange))
      -
      17447  {
      -
      17448  ranges.push_back(newRange);
      -
      17449  }
      -
      17450  }
      -
      17451 
      -
      17452  VkResult res = VK_SUCCESS;
      -
      17453  if(!ranges.empty())
      -
      17454  {
      -
      17455  switch(op)
      +
      17363  if(((1u << memTypeIndex) & memoryTypeBits) != 0)
      +
      17364  {
      +
      17365  VmaBlockVector* const pBlockVector = m_pBlockVectors[memTypeIndex];
      +
      17366  VMA_ASSERT(pBlockVector);
      +
      17367  VkResult localRes = pBlockVector->CheckCorruption();
      +
      17368  switch(localRes)
      +
      17369  {
      +
      17370  case VK_ERROR_FEATURE_NOT_PRESENT:
      +
      17371  break;
      +
      17372  case VK_SUCCESS:
      +
      17373  finalRes = VK_SUCCESS;
      +
      17374  break;
      +
      17375  default:
      +
      17376  return localRes;
      +
      17377  }
      +
      17378  }
      +
      17379  }
      +
      17380 
      +
      17381  // Process custom pools.
      +
      17382  {
      +
      17383  VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex);
      +
      17384  for(VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool))
      +
      17385  {
      +
      17386  if(((1u << pool->m_BlockVector.GetMemoryTypeIndex()) & memoryTypeBits) != 0)
      +
      17387  {
      +
      17388  VkResult localRes = pool->m_BlockVector.CheckCorruption();
      +
      17389  switch(localRes)
      +
      17390  {
      +
      17391  case VK_ERROR_FEATURE_NOT_PRESENT:
      +
      17392  break;
      +
      17393  case VK_SUCCESS:
      +
      17394  finalRes = VK_SUCCESS;
      +
      17395  break;
      +
      17396  default:
      +
      17397  return localRes;
      +
      17398  }
      +
      17399  }
      +
      17400  }
      +
      17401  }
      +
      17402 
      +
      17403  return finalRes;
      +
      17404 }
      +
      17405 
      +
      17406 void VmaAllocator_T::CreateLostAllocation(VmaAllocation* pAllocation)
      +
      17407 {
      +
      17408  *pAllocation = m_AllocationObjectAllocator.Allocate(VMA_FRAME_INDEX_LOST, false);
      +
      17409  (*pAllocation)->InitLost();
      +
      17410 }
      +
      17411 
      +
      17412 // An object that increments given atomic but decrements it back in the destructor unless Commit() is called.
      +
      17413 template<typename T>
      +
      17414 struct AtomicTransactionalIncrement
      +
      17415 {
      +
      17416 public:
      +
      17417  typedef std::atomic<T> AtomicT;
      +
      17418  ~AtomicTransactionalIncrement()
      +
      17419  {
      +
      17420  if(m_Atomic)
      +
      17421  --(*m_Atomic);
      +
      17422  }
      +
      17423  T Increment(AtomicT* atomic)
      +
      17424  {
      +
      17425  m_Atomic = atomic;
      +
      17426  return m_Atomic->fetch_add(1);
      +
      17427  }
      +
      17428  void Commit()
      +
      17429  {
      +
      17430  m_Atomic = nullptr;
      +
      17431  }
      +
      17432 
      +
      17433 private:
      +
      17434  AtomicT* m_Atomic = nullptr;
      +
      17435 };
      +
      17436 
      +
      17437 VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory)
      +
      17438 {
      +
      17439  AtomicTransactionalIncrement<uint32_t> deviceMemoryCountIncrement;
      +
      17440  const uint64_t prevDeviceMemoryCount = deviceMemoryCountIncrement.Increment(&m_DeviceMemoryCount);
      +
      17441 #if VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT
      +
      17442  if(prevDeviceMemoryCount >= m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount)
      +
      17443  {
      +
      17444  return VK_ERROR_TOO_MANY_OBJECTS;
      +
      17445  }
      +
      17446 #endif
      +
      17447 
      +
      17448  const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(pAllocateInfo->memoryTypeIndex);
      +
      17449 
      +
      17450  // HeapSizeLimit is in effect for this heap.
      +
      17451  if((m_HeapSizeLimitMask & (1u << heapIndex)) != 0)
      +
      17452  {
      +
      17453  const VkDeviceSize heapSize = m_MemProps.memoryHeaps[heapIndex].size;
      +
      17454  VkDeviceSize blockBytes = m_Budget.m_BlockBytes[heapIndex];
      +
      17455  for(;;)
      17456  {
      -
      17457  case VMA_CACHE_FLUSH:
      -
      17458  res = (*GetVulkanFunctions().vkFlushMappedMemoryRanges)(m_hDevice, (uint32_t)ranges.size(), ranges.data());
      -
      17459  break;
      -
      17460  case VMA_CACHE_INVALIDATE:
      -
      17461  res = (*GetVulkanFunctions().vkInvalidateMappedMemoryRanges)(m_hDevice, (uint32_t)ranges.size(), ranges.data());
      -
      17462  break;
      -
      17463  default:
      -
      17464  VMA_ASSERT(0);
      -
      17465  }
      -
      17466  }
      -
      17467  // else: Just ignore this call.
      -
      17468  return res;
      -
      17469 }
      -
      17470 
      -
      17471 void VmaAllocator_T::FreeDedicatedMemory(const VmaAllocation allocation)
      -
      17472 {
      -
      17473  VMA_ASSERT(allocation && allocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
      -
      17474 
      -
      17475  const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex();
      -
      17476  {
      -
      17477  VmaMutexLockWrite lock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
      -
      17478  AllocationVectorType* const pDedicatedAllocations = m_pDedicatedAllocations[memTypeIndex];
      -
      17479  VMA_ASSERT(pDedicatedAllocations);
      -
      17480  bool success = VmaVectorRemoveSorted<VmaPointerLess>(*pDedicatedAllocations, allocation);
      -
      17481  VMA_ASSERT(success);
      -
      17482  }
      -
      17483 
      -
      17484  VkDeviceMemory hMemory = allocation->GetMemory();
      -
      17485 
      -
      17486  /*
      -
      17487  There is no need to call this, because Vulkan spec allows to skip vkUnmapMemory
      -
      17488  before vkFreeMemory.
      -
      17489 
      -
      17490  if(allocation->GetMappedData() != VMA_NULL)
      -
      17491  {
      -
      17492  (*m_VulkanFunctions.vkUnmapMemory)(m_hDevice, hMemory);
      -
      17493  }
      -
      17494  */
      -
      17495 
      -
      17496  FreeVulkanMemory(memTypeIndex, allocation->GetSize(), hMemory);
      +
      17457  const VkDeviceSize blockBytesAfterAllocation = blockBytes + pAllocateInfo->allocationSize;
      +
      17458  if(blockBytesAfterAllocation > heapSize)
      +
      17459  {
      +
      17460  return VK_ERROR_OUT_OF_DEVICE_MEMORY;
      +
      17461  }
      +
      17462  if(m_Budget.m_BlockBytes[heapIndex].compare_exchange_strong(blockBytes, blockBytesAfterAllocation))
      +
      17463  {
      +
      17464  break;
      +
      17465  }
      +
      17466  }
      +
      17467  }
      +
      17468  else
      +
      17469  {
      +
      17470  m_Budget.m_BlockBytes[heapIndex] += pAllocateInfo->allocationSize;
      +
      17471  }
      +
      17472 
      +
      17473  // VULKAN CALL vkAllocateMemory.
      +
      17474  VkResult res = (*m_VulkanFunctions.vkAllocateMemory)(m_hDevice, pAllocateInfo, GetAllocationCallbacks(), pMemory);
      +
      17475 
      +
      17476  if(res == VK_SUCCESS)
      +
      17477  {
      +
      17478 #if VMA_MEMORY_BUDGET
      +
      17479  ++m_Budget.m_OperationsSinceBudgetFetch;
      +
      17480 #endif
      +
      17481 
      +
      17482  // Informative callback.
      +
      17483  if(m_DeviceMemoryCallbacks.pfnAllocate != VMA_NULL)
      +
      17484  {
      +
      17485  (*m_DeviceMemoryCallbacks.pfnAllocate)(this, pAllocateInfo->memoryTypeIndex, *pMemory, pAllocateInfo->allocationSize, m_DeviceMemoryCallbacks.pUserData);
      +
      17486  }
      +
      17487 
      +
      17488  deviceMemoryCountIncrement.Commit();
      +
      17489  }
      +
      17490  else
      +
      17491  {
      +
      17492  m_Budget.m_BlockBytes[heapIndex] -= pAllocateInfo->allocationSize;
      +
      17493  }
      +
      17494 
      +
      17495  return res;
      +
      17496 }
      17497 
      -
      17498  VMA_DEBUG_LOG(" Freed DedicatedMemory MemoryTypeIndex=%u", memTypeIndex);
      -
      17499 }
      -
      17500 
      -
      17501 uint32_t VmaAllocator_T::CalculateGpuDefragmentationMemoryTypeBits() const
      -
      17502 {
      -
      17503  VkBufferCreateInfo dummyBufCreateInfo;
      -
      17504  VmaFillGpuDefragmentationBufferCreateInfo(dummyBufCreateInfo);
      +
      17498 void VmaAllocator_T::FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, VkDeviceMemory hMemory)
      +
      17499 {
      +
      17500  // Informative callback.
      +
      17501  if(m_DeviceMemoryCallbacks.pfnFree != VMA_NULL)
      +
      17502  {
      +
      17503  (*m_DeviceMemoryCallbacks.pfnFree)(this, memoryType, hMemory, size, m_DeviceMemoryCallbacks.pUserData);
      +
      17504  }
      17505 
      -
      17506  uint32_t memoryTypeBits = 0;
      -
      17507 
      -
      17508  // Create buffer.
      -
      17509  VkBuffer buf = VK_NULL_HANDLE;
      -
      17510  VkResult res = (*GetVulkanFunctions().vkCreateBuffer)(
      -
      17511  m_hDevice, &dummyBufCreateInfo, GetAllocationCallbacks(), &buf);
      -
      17512  if(res == VK_SUCCESS)
      -
      17513  {
      -
      17514  // Query for supported memory types.
      -
      17515  VkMemoryRequirements memReq;
      -
      17516  (*GetVulkanFunctions().vkGetBufferMemoryRequirements)(m_hDevice, buf, &memReq);
      -
      17517  memoryTypeBits = memReq.memoryTypeBits;
      -
      17518 
      -
      17519  // Destroy buffer.
      -
      17520  (*GetVulkanFunctions().vkDestroyBuffer)(m_hDevice, buf, GetAllocationCallbacks());
      -
      17521  }
      -
      17522 
      -
      17523  return memoryTypeBits;
      -
      17524 }
      -
      17525 
      -
      17526 uint32_t VmaAllocator_T::CalculateGlobalMemoryTypeBits() const
      -
      17527 {
      -
      17528  // Make sure memory information is already fetched.
      -
      17529  VMA_ASSERT(GetMemoryTypeCount() > 0);
      -
      17530 
      -
      17531  uint32_t memoryTypeBits = UINT32_MAX;
      -
      17532 
      -
      17533  if(!m_UseAmdDeviceCoherentMemory)
      -
      17534  {
      -
      17535  // Exclude memory types that have VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD.
      -
      17536  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
      -
      17537  {
      -
      17538  if((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY) != 0)
      -
      17539  {
      -
      17540  memoryTypeBits &= ~(1u << memTypeIndex);
      -
      17541  }
      -
      17542  }
      -
      17543  }
      +
      17506  // VULKAN CALL vkFreeMemory.
      +
      17507  (*m_VulkanFunctions.vkFreeMemory)(m_hDevice, hMemory, GetAllocationCallbacks());
      +
      17508 
      +
      17509  m_Budget.m_BlockBytes[MemoryTypeIndexToHeapIndex(memoryType)] -= size;
      +
      17510 
      +
      17511  --m_DeviceMemoryCount;
      +
      17512 }
      +
      17513 
      +
      17514 VkResult VmaAllocator_T::BindVulkanBuffer(
      +
      17515  VkDeviceMemory memory,
      +
      17516  VkDeviceSize memoryOffset,
      +
      17517  VkBuffer buffer,
      +
      17518  const void* pNext)
      +
      17519 {
      +
      17520  if(pNext != VMA_NULL)
      +
      17521  {
      +
      17522 #if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2
      +
      17523  if((m_UseKhrBindMemory2 || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) &&
      +
      17524  m_VulkanFunctions.vkBindBufferMemory2KHR != VMA_NULL)
      +
      17525  {
      +
      17526  VkBindBufferMemoryInfoKHR bindBufferMemoryInfo = { VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR };
      +
      17527  bindBufferMemoryInfo.pNext = pNext;
      +
      17528  bindBufferMemoryInfo.buffer = buffer;
      +
      17529  bindBufferMemoryInfo.memory = memory;
      +
      17530  bindBufferMemoryInfo.memoryOffset = memoryOffset;
      +
      17531  return (*m_VulkanFunctions.vkBindBufferMemory2KHR)(m_hDevice, 1, &bindBufferMemoryInfo);
      +
      17532  }
      +
      17533  else
      +
      17534 #endif // #if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2
      +
      17535  {
      +
      17536  return VK_ERROR_EXTENSION_NOT_PRESENT;
      +
      17537  }
      +
      17538  }
      +
      17539  else
      +
      17540  {
      +
      17541  return (*m_VulkanFunctions.vkBindBufferMemory)(m_hDevice, buffer, memory, memoryOffset);
      +
      17542  }
      +
      17543 }
      17544 
      -
      17545  return memoryTypeBits;
      -
      17546 }
      -
      17547 
      -
      17548 bool VmaAllocator_T::GetFlushOrInvalidateRange(
      -
      17549  VmaAllocation allocation,
      -
      17550  VkDeviceSize offset, VkDeviceSize size,
      -
      17551  VkMappedMemoryRange& outRange) const
      -
      17552 {
      -
      17553  const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex();
      -
      17554  if(size > 0 && IsMemoryTypeNonCoherent(memTypeIndex))
      -
      17555  {
      -
      17556  const VkDeviceSize nonCoherentAtomSize = m_PhysicalDeviceProperties.limits.nonCoherentAtomSize;
      -
      17557  const VkDeviceSize allocationSize = allocation->GetSize();
      -
      17558  VMA_ASSERT(offset <= allocationSize);
      -
      17559 
      -
      17560  outRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
      -
      17561  outRange.pNext = VMA_NULL;
      -
      17562  outRange.memory = allocation->GetMemory();
      -
      17563 
      -
      17564  switch(allocation->GetType())
      -
      17565  {
      -
      17566  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
      -
      17567  outRange.offset = VmaAlignDown(offset, nonCoherentAtomSize);
      -
      17568  if(size == VK_WHOLE_SIZE)
      -
      17569  {
      -
      17570  outRange.size = allocationSize - outRange.offset;
      -
      17571  }
      -
      17572  else
      -
      17573  {
      -
      17574  VMA_ASSERT(offset + size <= allocationSize);
      -
      17575  outRange.size = VMA_MIN(
      -
      17576  VmaAlignUp(size + (offset - outRange.offset), nonCoherentAtomSize),
      -
      17577  allocationSize - outRange.offset);
      -
      17578  }
      -
      17579  break;
      -
      17580  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
      -
      17581  {
      -
      17582  // 1. Still within this allocation.
      -
      17583  outRange.offset = VmaAlignDown(offset, nonCoherentAtomSize);
      -
      17584  if(size == VK_WHOLE_SIZE)
      -
      17585  {
      -
      17586  size = allocationSize - offset;
      -
      17587  }
      -
      17588  else
      -
      17589  {
      -
      17590  VMA_ASSERT(offset + size <= allocationSize);
      -
      17591  }
      -
      17592  outRange.size = VmaAlignUp(size + (offset - outRange.offset), nonCoherentAtomSize);
      -
      17593 
      -
      17594  // 2. Adjust to whole block.
      -
      17595  const VkDeviceSize allocationOffset = allocation->GetOffset();
      -
      17596  VMA_ASSERT(allocationOffset % nonCoherentAtomSize == 0);
      -
      17597  const VkDeviceSize blockSize = allocation->GetBlock()->m_pMetadata->GetSize();
      -
      17598  outRange.offset += allocationOffset;
      -
      17599  outRange.size = VMA_MIN(outRange.size, blockSize - outRange.offset);
      -
      17600 
      -
      17601  break;
      -
      17602  }
      -
      17603  default:
      -
      17604  VMA_ASSERT(0);
      -
      17605  }
      -
      17606  return true;
      -
      17607  }
      -
      17608  return false;
      -
      17609 }
      -
      17610 
      -
      17611 #if VMA_MEMORY_BUDGET
      -
      17612 
      -
      17613 void VmaAllocator_T::UpdateVulkanBudget()
      -
      17614 {
      -
      17615  VMA_ASSERT(m_UseExtMemoryBudget);
      -
      17616 
      -
      17617  VkPhysicalDeviceMemoryProperties2KHR memProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR };
      -
      17618 
      -
      17619  VkPhysicalDeviceMemoryBudgetPropertiesEXT budgetProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT };
      -
      17620  VmaPnextChainPushFront(&memProps, &budgetProps);
      -
      17621 
      -
      17622  GetVulkanFunctions().vkGetPhysicalDeviceMemoryProperties2KHR(m_PhysicalDevice, &memProps);
      +
      17545 VkResult VmaAllocator_T::BindVulkanImage(
      +
      17546  VkDeviceMemory memory,
      +
      17547  VkDeviceSize memoryOffset,
      +
      17548  VkImage image,
      +
      17549  const void* pNext)
      +
      17550 {
      +
      17551  if(pNext != VMA_NULL)
      +
      17552  {
      +
      17553 #if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2
      +
      17554  if((m_UseKhrBindMemory2 || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) &&
      +
      17555  m_VulkanFunctions.vkBindImageMemory2KHR != VMA_NULL)
      +
      17556  {
      +
      17557  VkBindImageMemoryInfoKHR bindBufferMemoryInfo = { VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR };
      +
      17558  bindBufferMemoryInfo.pNext = pNext;
      +
      17559  bindBufferMemoryInfo.image = image;
      +
      17560  bindBufferMemoryInfo.memory = memory;
      +
      17561  bindBufferMemoryInfo.memoryOffset = memoryOffset;
      +
      17562  return (*m_VulkanFunctions.vkBindImageMemory2KHR)(m_hDevice, 1, &bindBufferMemoryInfo);
      +
      17563  }
      +
      17564  else
      +
      17565 #endif // #if VMA_BIND_MEMORY2
      +
      17566  {
      +
      17567  return VK_ERROR_EXTENSION_NOT_PRESENT;
      +
      17568  }
      +
      17569  }
      +
      17570  else
      +
      17571  {
      +
      17572  return (*m_VulkanFunctions.vkBindImageMemory)(m_hDevice, image, memory, memoryOffset);
      +
      17573  }
      +
      17574 }
      +
      17575 
      +
      17576 VkResult VmaAllocator_T::Map(VmaAllocation hAllocation, void** ppData)
      +
      17577 {
      +
      17578  if(hAllocation->CanBecomeLost())
      +
      17579  {
      +
      17580  return VK_ERROR_MEMORY_MAP_FAILED;
      +
      17581  }
      +
      17582 
      +
      17583  switch(hAllocation->GetType())
      +
      17584  {
      +
      17585  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
      +
      17586  {
      +
      17587  VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock();
      +
      17588  char *pBytes = VMA_NULL;
      +
      17589  VkResult res = pBlock->Map(this, 1, (void**)&pBytes);
      +
      17590  if(res == VK_SUCCESS)
      +
      17591  {
      +
      17592  *ppData = pBytes + (ptrdiff_t)hAllocation->GetOffset();
      +
      17593  hAllocation->BlockAllocMap();
      +
      17594  }
      +
      17595  return res;
      +
      17596  }
      +
      17597  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
      +
      17598  return hAllocation->DedicatedAllocMap(this, ppData);
      +
      17599  default:
      +
      17600  VMA_ASSERT(0);
      +
      17601  return VK_ERROR_MEMORY_MAP_FAILED;
      +
      17602  }
      +
      17603 }
      +
      17604 
      +
      17605 void VmaAllocator_T::Unmap(VmaAllocation hAllocation)
      +
      17606 {
      +
      17607  switch(hAllocation->GetType())
      +
      17608  {
      +
      17609  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
      +
      17610  {
      +
      17611  VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock();
      +
      17612  hAllocation->BlockAllocUnmap();
      +
      17613  pBlock->Unmap(this, 1);
      +
      17614  }
      +
      17615  break;
      +
      17616  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
      +
      17617  hAllocation->DedicatedAllocUnmap(this);
      +
      17618  break;
      +
      17619  default:
      +
      17620  VMA_ASSERT(0);
      +
      17621  }
      +
      17622 }
      17623 
      -
      17624  {
      -
      17625  VmaMutexLockWrite lockWrite(m_Budget.m_BudgetMutex, m_UseMutex);
      -
      17626 
      -
      17627  for(uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex)
      -
      17628  {
      -
      17629  m_Budget.m_VulkanUsage[heapIndex] = budgetProps.heapUsage[heapIndex];
      -
      17630  m_Budget.m_VulkanBudget[heapIndex] = budgetProps.heapBudget[heapIndex];
      -
      17631  m_Budget.m_BlockBytesAtBudgetFetch[heapIndex] = m_Budget.m_BlockBytes[heapIndex].load();
      -
      17632 
      -
      17633  // Some bugged drivers return the budget incorrectly, e.g. 0 or much bigger than heap size.
      -
      17634  if(m_Budget.m_VulkanBudget[heapIndex] == 0)
      -
      17635  {
      -
      17636  m_Budget.m_VulkanBudget[heapIndex] = m_MemProps.memoryHeaps[heapIndex].size * 8 / 10; // 80% heuristics.
      -
      17637  }
      -
      17638  else if(m_Budget.m_VulkanBudget[heapIndex] > m_MemProps.memoryHeaps[heapIndex].size)
      -
      17639  {
      -
      17640  m_Budget.m_VulkanBudget[heapIndex] = m_MemProps.memoryHeaps[heapIndex].size;
      -
      17641  }
      -
      17642  if(m_Budget.m_VulkanUsage[heapIndex] == 0 && m_Budget.m_BlockBytesAtBudgetFetch[heapIndex] > 0)
      -
      17643  {
      -
      17644  m_Budget.m_VulkanUsage[heapIndex] = m_Budget.m_BlockBytesAtBudgetFetch[heapIndex];
      -
      17645  }
      -
      17646  }
      -
      17647  m_Budget.m_OperationsSinceBudgetFetch = 0;
      -
      17648  }
      -
      17649 }
      -
      17650 
      -
      17651 #endif // #if VMA_MEMORY_BUDGET
      -
      17652 
      -
      17653 void VmaAllocator_T::FillAllocation(const VmaAllocation hAllocation, uint8_t pattern)
      +
      17624 VkResult VmaAllocator_T::BindBufferMemory(
      +
      17625  VmaAllocation hAllocation,
      +
      17626  VkDeviceSize allocationLocalOffset,
      +
      17627  VkBuffer hBuffer,
      +
      17628  const void* pNext)
      +
      17629 {
      +
      17630  VkResult res = VK_SUCCESS;
      +
      17631  switch(hAllocation->GetType())
      +
      17632  {
      +
      17633  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
      +
      17634  res = BindVulkanBuffer(hAllocation->GetMemory(), allocationLocalOffset, hBuffer, pNext);
      +
      17635  break;
      +
      17636  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
      +
      17637  {
      +
      17638  VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock();
      +
      17639  VMA_ASSERT(pBlock && "Binding buffer to allocation that doesn't belong to any block. Is the allocation lost?");
      +
      17640  res = pBlock->BindBufferMemory(this, hAllocation, allocationLocalOffset, hBuffer, pNext);
      +
      17641  break;
      +
      17642  }
      +
      17643  default:
      +
      17644  VMA_ASSERT(0);
      +
      17645  }
      +
      17646  return res;
      +
      17647 }
      +
      17648 
      +
      17649 VkResult VmaAllocator_T::BindImageMemory(
      +
      17650  VmaAllocation hAllocation,
      +
      17651  VkDeviceSize allocationLocalOffset,
      +
      17652  VkImage hImage,
      +
      17653  const void* pNext)
      17654 {
      -
      17655  if(VMA_DEBUG_INITIALIZE_ALLOCATIONS &&
      -
      17656  !hAllocation->CanBecomeLost() &&
      -
      17657  (m_MemProps.memoryTypes[hAllocation->GetMemoryTypeIndex()].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
      -
      17658  {
      -
      17659  void* pData = VMA_NULL;
      -
      17660  VkResult res = Map(hAllocation, &pData);
      -
      17661  if(res == VK_SUCCESS)
      -
      17662  {
      -
      17663  memset(pData, (int)pattern, (size_t)hAllocation->GetSize());
      -
      17664  FlushOrInvalidateAllocation(hAllocation, 0, VK_WHOLE_SIZE, VMA_CACHE_FLUSH);
      -
      17665  Unmap(hAllocation);
      -
      17666  }
      -
      17667  else
      -
      17668  {
      -
      17669  VMA_ASSERT(0 && "VMA_DEBUG_INITIALIZE_ALLOCATIONS is enabled, but couldn't map memory to fill allocation.");
      -
      17670  }
      -
      17671  }
      +
      17655  VkResult res = VK_SUCCESS;
      +
      17656  switch(hAllocation->GetType())
      +
      17657  {
      +
      17658  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
      +
      17659  res = BindVulkanImage(hAllocation->GetMemory(), allocationLocalOffset, hImage, pNext);
      +
      17660  break;
      +
      17661  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
      +
      17662  {
      +
      17663  VmaDeviceMemoryBlock* pBlock = hAllocation->GetBlock();
      +
      17664  VMA_ASSERT(pBlock && "Binding image to allocation that doesn't belong to any block. Is the allocation lost?");
      +
      17665  res = pBlock->BindImageMemory(this, hAllocation, allocationLocalOffset, hImage, pNext);
      +
      17666  break;
      +
      17667  }
      +
      17668  default:
      +
      17669  VMA_ASSERT(0);
      +
      17670  }
      +
      17671  return res;
      17672 }
      17673 
      -
      17674 uint32_t VmaAllocator_T::GetGpuDefragmentationMemoryTypeBits()
      -
      17675 {
      -
      17676  uint32_t memoryTypeBits = m_GpuDefragmentationMemoryTypeBits.load();
      -
      17677  if(memoryTypeBits == UINT32_MAX)
      -
      17678  {
      -
      17679  memoryTypeBits = CalculateGpuDefragmentationMemoryTypeBits();
      -
      17680  m_GpuDefragmentationMemoryTypeBits.store(memoryTypeBits);
      -
      17681  }
      -
      17682  return memoryTypeBits;
      -
      17683 }
      -
      17684 
      -
      17685 #if VMA_STATS_STRING_ENABLED
      -
      17686 
      -
      17687 void VmaAllocator_T::PrintDetailedMap(VmaJsonWriter& json)
      -
      17688 {
      -
      17689  bool dedicatedAllocationsStarted = false;
      -
      17690  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
      -
      17691  {
      -
      17692  VmaMutexLockRead dedicatedAllocationsLock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
      -
      17693  AllocationVectorType* const pDedicatedAllocVector = m_pDedicatedAllocations[memTypeIndex];
      -
      17694  VMA_ASSERT(pDedicatedAllocVector);
      -
      17695  if(pDedicatedAllocVector->empty() == false)
      -
      17696  {
      -
      17697  if(dedicatedAllocationsStarted == false)
      -
      17698  {
      -
      17699  dedicatedAllocationsStarted = true;
      -
      17700  json.WriteString("DedicatedAllocations");
      -
      17701  json.BeginObject();
      -
      17702  }
      -
      17703 
      -
      17704  json.BeginString("Type ");
      -
      17705  json.ContinueString(memTypeIndex);
      -
      17706  json.EndString();
      -
      17707 
      -
      17708  json.BeginArray();
      +
      17674 VkResult VmaAllocator_T::FlushOrInvalidateAllocation(
      +
      17675  VmaAllocation hAllocation,
      +
      17676  VkDeviceSize offset, VkDeviceSize size,
      +
      17677  VMA_CACHE_OPERATION op)
      +
      17678 {
      +
      17679  VkResult res = VK_SUCCESS;
      +
      17680 
      +
      17681  VkMappedMemoryRange memRange = {};
      +
      17682  if(GetFlushOrInvalidateRange(hAllocation, offset, size, memRange))
      +
      17683  {
      +
      17684  switch(op)
      +
      17685  {
      +
      17686  case VMA_CACHE_FLUSH:
      +
      17687  res = (*GetVulkanFunctions().vkFlushMappedMemoryRanges)(m_hDevice, 1, &memRange);
      +
      17688  break;
      +
      17689  case VMA_CACHE_INVALIDATE:
      +
      17690  res = (*GetVulkanFunctions().vkInvalidateMappedMemoryRanges)(m_hDevice, 1, &memRange);
      +
      17691  break;
      +
      17692  default:
      +
      17693  VMA_ASSERT(0);
      +
      17694  }
      +
      17695  }
      +
      17696  // else: Just ignore this call.
      +
      17697  return res;
      +
      17698 }
      +
      17699 
      +
      17700 VkResult VmaAllocator_T::FlushOrInvalidateAllocations(
      +
      17701  uint32_t allocationCount,
      +
      17702  const VmaAllocation* allocations,
      +
      17703  const VkDeviceSize* offsets, const VkDeviceSize* sizes,
      +
      17704  VMA_CACHE_OPERATION op)
      +
      17705 {
      +
      17706  typedef VmaStlAllocator<VkMappedMemoryRange> RangeAllocator;
      +
      17707  typedef VmaSmallVector<VkMappedMemoryRange, RangeAllocator, 16> RangeVector;
      +
      17708  RangeVector ranges = RangeVector(RangeAllocator(GetAllocationCallbacks()));
      17709 
      -
      17710  for(size_t i = 0; i < pDedicatedAllocVector->size(); ++i)
      -
      17711  {
      -
      17712  json.BeginObject(true);
      -
      17713  const VmaAllocation hAlloc = (*pDedicatedAllocVector)[i];
      -
      17714  hAlloc->PrintParameters(json);
      -
      17715  json.EndObject();
      -
      17716  }
      -
      17717 
      -
      17718  json.EndArray();
      +
      17710  for(uint32_t allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
      +
      17711  {
      +
      17712  const VmaAllocation alloc = allocations[allocIndex];
      +
      17713  const VkDeviceSize offset = offsets != VMA_NULL ? offsets[allocIndex] : 0;
      +
      17714  const VkDeviceSize size = sizes != VMA_NULL ? sizes[allocIndex] : VK_WHOLE_SIZE;
      +
      17715  VkMappedMemoryRange newRange;
      +
      17716  if(GetFlushOrInvalidateRange(alloc, offset, size, newRange))
      +
      17717  {
      +
      17718  ranges.push_back(newRange);
      17719  }
      17720  }
      -
      17721  if(dedicatedAllocationsStarted)
      -
      17722  {
      -
      17723  json.EndObject();
      -
      17724  }
      -
      17725 
      -
      17726  {
      -
      17727  bool allocationsStarted = false;
      -
      17728  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
      -
      17729  {
      -
      17730  if(m_pBlockVectors[memTypeIndex]->IsEmpty() == false)
      -
      17731  {
      -
      17732  if(allocationsStarted == false)
      -
      17733  {
      -
      17734  allocationsStarted = true;
      -
      17735  json.WriteString("DefaultPools");
      -
      17736  json.BeginObject();
      -
      17737  }
      -
      17738 
      -
      17739  json.BeginString("Type ");
      -
      17740  json.ContinueString(memTypeIndex);
      -
      17741  json.EndString();
      -
      17742 
      -
      17743  m_pBlockVectors[memTypeIndex]->PrintDetailedMap(json);
      -
      17744  }
      -
      17745  }
      -
      17746  if(allocationsStarted)
      -
      17747  {
      -
      17748  json.EndObject();
      -
      17749  }
      +
      17721 
      +
      17722  VkResult res = VK_SUCCESS;
      +
      17723  if(!ranges.empty())
      +
      17724  {
      +
      17725  switch(op)
      +
      17726  {
      +
      17727  case VMA_CACHE_FLUSH:
      +
      17728  res = (*GetVulkanFunctions().vkFlushMappedMemoryRanges)(m_hDevice, (uint32_t)ranges.size(), ranges.data());
      +
      17729  break;
      +
      17730  case VMA_CACHE_INVALIDATE:
      +
      17731  res = (*GetVulkanFunctions().vkInvalidateMappedMemoryRanges)(m_hDevice, (uint32_t)ranges.size(), ranges.data());
      +
      17732  break;
      +
      17733  default:
      +
      17734  VMA_ASSERT(0);
      +
      17735  }
      +
      17736  }
      +
      17737  // else: Just ignore this call.
      +
      17738  return res;
      +
      17739 }
      +
      17740 
      +
      17741 void VmaAllocator_T::FreeDedicatedMemory(const VmaAllocation allocation)
      +
      17742 {
      +
      17743  VMA_ASSERT(allocation && allocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
      +
      17744 
      +
      17745  const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex();
      +
      17746  {
      +
      17747  VmaMutexLockWrite lock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
      +
      17748  DedicatedAllocationLinkedList& dedicatedAllocations = m_DedicatedAllocations[memTypeIndex];
      +
      17749  dedicatedAllocations.Remove(allocation);
      17750  }
      17751 
      -
      17752  // Custom pools
      -
      17753  {
      -
      17754  VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex);
      -
      17755  const size_t poolCount = m_Pools.size();
      -
      17756  if(poolCount > 0)
      -
      17757  {
      -
      17758  json.WriteString("Pools");
      -
      17759  json.BeginObject();
      -
      17760  for(size_t poolIndex = 0; poolIndex < poolCount; ++poolIndex)
      -
      17761  {
      -
      17762  json.BeginString();
      -
      17763  json.ContinueString(m_Pools[poolIndex]->GetId());
      -
      17764  json.EndString();
      +
      17752  VkDeviceMemory hMemory = allocation->GetMemory();
      +
      17753 
      +
      17754  /*
      +
      17755  There is no need to call this, because Vulkan spec allows to skip vkUnmapMemory
      +
      17756  before vkFreeMemory.
      +
      17757 
      +
      17758  if(allocation->GetMappedData() != VMA_NULL)
      +
      17759  {
      +
      17760  (*m_VulkanFunctions.vkUnmapMemory)(m_hDevice, hMemory);
      +
      17761  }
      +
      17762  */
      +
      17763 
      +
      17764  FreeVulkanMemory(memTypeIndex, allocation->GetSize(), hMemory);
      17765 
      -
      17766  m_Pools[poolIndex]->m_BlockVector.PrintDetailedMap(json);
      -
      17767  }
      -
      17768  json.EndObject();
      -
      17769  }
      -
      17770  }
      -
      17771 }
      -
      17772 
      -
      17773 #endif // #if VMA_STATS_STRING_ENABLED
      -
      17774 
      -
      17776 // Public interface
      -
      17777 
      -
      17778 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator(
      -
      17779  const VmaAllocatorCreateInfo* pCreateInfo,
      -
      17780  VmaAllocator* pAllocator)
      -
      17781 {
      -
      17782  VMA_ASSERT(pCreateInfo && pAllocator);
      -
      17783  VMA_ASSERT(pCreateInfo->vulkanApiVersion == 0 ||
      -
      17784  (VK_VERSION_MAJOR(pCreateInfo->vulkanApiVersion) == 1 && VK_VERSION_MINOR(pCreateInfo->vulkanApiVersion) <= 2));
      -
      17785  VMA_DEBUG_LOG("vmaCreateAllocator");
      -
      17786  *pAllocator = vma_new(pCreateInfo->pAllocationCallbacks, VmaAllocator_T)(pCreateInfo);
      -
      17787  return (*pAllocator)->Init(pCreateInfo);
      -
      17788 }
      -
      17789 
      -
      17790 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyAllocator(
      -
      17791  VmaAllocator allocator)
      -
      17792 {
      -
      17793  if(allocator != VK_NULL_HANDLE)
      -
      17794  {
      -
      17795  VMA_DEBUG_LOG("vmaDestroyAllocator");
      -
      17796  VkAllocationCallbacks allocationCallbacks = allocator->m_AllocationCallbacks;
      -
      17797  vma_delete(&allocationCallbacks, allocator);
      -
      17798  }
      -
      17799 }
      +
      17766  VMA_DEBUG_LOG(" Freed DedicatedMemory MemoryTypeIndex=%u", memTypeIndex);
      +
      17767 }
      +
      17768 
      +
      17769 uint32_t VmaAllocator_T::CalculateGpuDefragmentationMemoryTypeBits() const
      +
      17770 {
      +
      17771  VkBufferCreateInfo dummyBufCreateInfo;
      +
      17772  VmaFillGpuDefragmentationBufferCreateInfo(dummyBufCreateInfo);
      +
      17773 
      +
      17774  uint32_t memoryTypeBits = 0;
      +
      17775 
      +
      17776  // Create buffer.
      +
      17777  VkBuffer buf = VK_NULL_HANDLE;
      +
      17778  VkResult res = (*GetVulkanFunctions().vkCreateBuffer)(
      +
      17779  m_hDevice, &dummyBufCreateInfo, GetAllocationCallbacks(), &buf);
      +
      17780  if(res == VK_SUCCESS)
      +
      17781  {
      +
      17782  // Query for supported memory types.
      +
      17783  VkMemoryRequirements memReq;
      +
      17784  (*GetVulkanFunctions().vkGetBufferMemoryRequirements)(m_hDevice, buf, &memReq);
      +
      17785  memoryTypeBits = memReq.memoryTypeBits;
      +
      17786 
      +
      17787  // Destroy buffer.
      +
      17788  (*GetVulkanFunctions().vkDestroyBuffer)(m_hDevice, buf, GetAllocationCallbacks());
      +
      17789  }
      +
      17790 
      +
      17791  return memoryTypeBits;
      +
      17792 }
      +
      17793 
      +
      17794 uint32_t VmaAllocator_T::CalculateGlobalMemoryTypeBits() const
      +
      17795 {
      +
      17796  // Make sure memory information is already fetched.
      +
      17797  VMA_ASSERT(GetMemoryTypeCount() > 0);
      +
      17798 
      +
      17799  uint32_t memoryTypeBits = UINT32_MAX;
      17800 
      -
      17801 VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocatorInfo(VmaAllocator allocator, VmaAllocatorInfo* pAllocatorInfo)
      -
      17802 {
      -
      17803  VMA_ASSERT(allocator && pAllocatorInfo);
      -
      17804  pAllocatorInfo->instance = allocator->m_hInstance;
      -
      17805  pAllocatorInfo->physicalDevice = allocator->GetPhysicalDevice();
      -
      17806  pAllocatorInfo->device = allocator->m_hDevice;
      -
      17807 }
      -
      17808 
      -
      17809 VMA_CALL_PRE void VMA_CALL_POST vmaGetPhysicalDeviceProperties(
      -
      17810  VmaAllocator allocator,
      -
      17811  const VkPhysicalDeviceProperties **ppPhysicalDeviceProperties)
      -
      17812 {
      -
      17813  VMA_ASSERT(allocator && ppPhysicalDeviceProperties);
      -
      17814  *ppPhysicalDeviceProperties = &allocator->m_PhysicalDeviceProperties;
      -
      17815 }
      -
      17816 
      -
      17817 VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryProperties(
      -
      17818  VmaAllocator allocator,
      -
      17819  const VkPhysicalDeviceMemoryProperties** ppPhysicalDeviceMemoryProperties)
      -
      17820 {
      -
      17821  VMA_ASSERT(allocator && ppPhysicalDeviceMemoryProperties);
      -
      17822  *ppPhysicalDeviceMemoryProperties = &allocator->m_MemProps;
      -
      17823 }
      -
      17824 
      -
      17825 VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryTypeProperties(
      -
      17826  VmaAllocator allocator,
      -
      17827  uint32_t memoryTypeIndex,
      -
      17828  VkMemoryPropertyFlags* pFlags)
      -
      17829 {
      -
      17830  VMA_ASSERT(allocator && pFlags);
      -
      17831  VMA_ASSERT(memoryTypeIndex < allocator->GetMemoryTypeCount());
      -
      17832  *pFlags = allocator->m_MemProps.memoryTypes[memoryTypeIndex].propertyFlags;
      -
      17833 }
      -
      17834 
      -
      17835 VMA_CALL_PRE void VMA_CALL_POST vmaSetCurrentFrameIndex(
      -
      17836  VmaAllocator allocator,
      -
      17837  uint32_t frameIndex)
      -
      17838 {
      -
      17839  VMA_ASSERT(allocator);
      -
      17840  VMA_ASSERT(frameIndex != VMA_FRAME_INDEX_LOST);
      -
      17841 
      -
      17842  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      17843 
      -
      17844  allocator->SetCurrentFrameIndex(frameIndex);
      -
      17845 }
      -
      17846 
      -
      17847 VMA_CALL_PRE void VMA_CALL_POST vmaCalculateStats(
      -
      17848  VmaAllocator allocator,
      -
      17849  VmaStats* pStats)
      -
      17850 {
      -
      17851  VMA_ASSERT(allocator && pStats);
      -
      17852  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      17853  allocator->CalculateStats(pStats);
      -
      17854 }
      -
      17855 
      -
      17856 VMA_CALL_PRE void VMA_CALL_POST vmaGetBudget(
      -
      17857  VmaAllocator allocator,
      -
      17858  VmaBudget* pBudget)
      -
      17859 {
      -
      17860  VMA_ASSERT(allocator && pBudget);
      -
      17861  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      17862  allocator->GetBudget(pBudget, 0, allocator->GetMemoryHeapCount());
      -
      17863 }
      -
      17864 
      -
      17865 #if VMA_STATS_STRING_ENABLED
      -
      17866 
      -
      17867 VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString(
      -
      17868  VmaAllocator allocator,
      -
      17869  char** ppStatsString,
      -
      17870  VkBool32 detailedMap)
      -
      17871 {
      -
      17872  VMA_ASSERT(allocator && ppStatsString);
      -
      17873  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      17874 
      -
      17875  VmaStringBuilder sb(allocator);
      -
      17876  {
      -
      17877  VmaJsonWriter json(allocator->GetAllocationCallbacks(), sb);
      -
      17878  json.BeginObject();
      -
      17879 
      -
      17880  VmaBudget budget[VK_MAX_MEMORY_HEAPS];
      -
      17881  allocator->GetBudget(budget, 0, allocator->GetMemoryHeapCount());
      -
      17882 
      -
      17883  VmaStats stats;
      -
      17884  allocator->CalculateStats(&stats);
      -
      17885 
      -
      17886  json.WriteString("Total");
      -
      17887  VmaPrintStatInfo(json, stats.total);
      -
      17888 
      -
      17889  for(uint32_t heapIndex = 0; heapIndex < allocator->GetMemoryHeapCount(); ++heapIndex)
      -
      17890  {
      -
      17891  json.BeginString("Heap ");
      -
      17892  json.ContinueString(heapIndex);
      -
      17893  json.EndString();
      -
      17894  json.BeginObject();
      -
      17895 
      -
      17896  json.WriteString("Size");
      -
      17897  json.WriteNumber(allocator->m_MemProps.memoryHeaps[heapIndex].size);
      -
      17898 
      -
      17899  json.WriteString("Flags");
      -
      17900  json.BeginArray(true);
      -
      17901  if((allocator->m_MemProps.memoryHeaps[heapIndex].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0)
      -
      17902  {
      -
      17903  json.WriteString("DEVICE_LOCAL");
      -
      17904  }
      -
      17905  json.EndArray();
      -
      17906 
      -
      17907  json.WriteString("Budget");
      -
      17908  json.BeginObject();
      -
      17909  {
      -
      17910  json.WriteString("BlockBytes");
      -
      17911  json.WriteNumber(budget[heapIndex].blockBytes);
      -
      17912  json.WriteString("AllocationBytes");
      -
      17913  json.WriteNumber(budget[heapIndex].allocationBytes);
      -
      17914  json.WriteString("Usage");
      -
      17915  json.WriteNumber(budget[heapIndex].usage);
      -
      17916  json.WriteString("Budget");
      -
      17917  json.WriteNumber(budget[heapIndex].budget);
      -
      17918  }
      -
      17919  json.EndObject();
      +
      17801  if(!m_UseAmdDeviceCoherentMemory)
      +
      17802  {
      +
      17803  // Exclude memory types that have VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD.
      +
      17804  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
      +
      17805  {
      +
      17806  if((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY) != 0)
      +
      17807  {
      +
      17808  memoryTypeBits &= ~(1u << memTypeIndex);
      +
      17809  }
      +
      17810  }
      +
      17811  }
      +
      17812 
      +
      17813  return memoryTypeBits;
      +
      17814 }
      +
      17815 
      +
      17816 bool VmaAllocator_T::GetFlushOrInvalidateRange(
      +
      17817  VmaAllocation allocation,
      +
      17818  VkDeviceSize offset, VkDeviceSize size,
      +
      17819  VkMappedMemoryRange& outRange) const
      +
      17820 {
      +
      17821  const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex();
      +
      17822  if(size > 0 && IsMemoryTypeNonCoherent(memTypeIndex))
      +
      17823  {
      +
      17824  const VkDeviceSize nonCoherentAtomSize = m_PhysicalDeviceProperties.limits.nonCoherentAtomSize;
      +
      17825  const VkDeviceSize allocationSize = allocation->GetSize();
      +
      17826  VMA_ASSERT(offset <= allocationSize);
      +
      17827 
      +
      17828  outRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
      +
      17829  outRange.pNext = VMA_NULL;
      +
      17830  outRange.memory = allocation->GetMemory();
      +
      17831 
      +
      17832  switch(allocation->GetType())
      +
      17833  {
      +
      17834  case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
      +
      17835  outRange.offset = VmaAlignDown(offset, nonCoherentAtomSize);
      +
      17836  if(size == VK_WHOLE_SIZE)
      +
      17837  {
      +
      17838  outRange.size = allocationSize - outRange.offset;
      +
      17839  }
      +
      17840  else
      +
      17841  {
      +
      17842  VMA_ASSERT(offset + size <= allocationSize);
      +
      17843  outRange.size = VMA_MIN(
      +
      17844  VmaAlignUp(size + (offset - outRange.offset), nonCoherentAtomSize),
      +
      17845  allocationSize - outRange.offset);
      +
      17846  }
      +
      17847  break;
      +
      17848  case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
      +
      17849  {
      +
      17850  // 1. Still within this allocation.
      +
      17851  outRange.offset = VmaAlignDown(offset, nonCoherentAtomSize);
      +
      17852  if(size == VK_WHOLE_SIZE)
      +
      17853  {
      +
      17854  size = allocationSize - offset;
      +
      17855  }
      +
      17856  else
      +
      17857  {
      +
      17858  VMA_ASSERT(offset + size <= allocationSize);
      +
      17859  }
      +
      17860  outRange.size = VmaAlignUp(size + (offset - outRange.offset), nonCoherentAtomSize);
      +
      17861 
      +
      17862  // 2. Adjust to whole block.
      +
      17863  const VkDeviceSize allocationOffset = allocation->GetOffset();
      +
      17864  VMA_ASSERT(allocationOffset % nonCoherentAtomSize == 0);
      +
      17865  const VkDeviceSize blockSize = allocation->GetBlock()->m_pMetadata->GetSize();
      +
      17866  outRange.offset += allocationOffset;
      +
      17867  outRange.size = VMA_MIN(outRange.size, blockSize - outRange.offset);
      +
      17868 
      +
      17869  break;
      +
      17870  }
      +
      17871  default:
      +
      17872  VMA_ASSERT(0);
      +
      17873  }
      +
      17874  return true;
      +
      17875  }
      +
      17876  return false;
      +
      17877 }
      +
      17878 
      +
      17879 #if VMA_MEMORY_BUDGET
      +
      17880 
      +
      17881 void VmaAllocator_T::UpdateVulkanBudget()
      +
      17882 {
      +
      17883  VMA_ASSERT(m_UseExtMemoryBudget);
      +
      17884 
      +
      17885  VkPhysicalDeviceMemoryProperties2KHR memProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR };
      +
      17886 
      +
      17887  VkPhysicalDeviceMemoryBudgetPropertiesEXT budgetProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT };
      +
      17888  VmaPnextChainPushFront(&memProps, &budgetProps);
      +
      17889 
      +
      17890  GetVulkanFunctions().vkGetPhysicalDeviceMemoryProperties2KHR(m_PhysicalDevice, &memProps);
      +
      17891 
      +
      17892  {
      +
      17893  VmaMutexLockWrite lockWrite(m_Budget.m_BudgetMutex, m_UseMutex);
      +
      17894 
      +
      17895  for(uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex)
      +
      17896  {
      +
      17897  m_Budget.m_VulkanUsage[heapIndex] = budgetProps.heapUsage[heapIndex];
      +
      17898  m_Budget.m_VulkanBudget[heapIndex] = budgetProps.heapBudget[heapIndex];
      +
      17899  m_Budget.m_BlockBytesAtBudgetFetch[heapIndex] = m_Budget.m_BlockBytes[heapIndex].load();
      +
      17900 
      +
      17901  // Some bugged drivers return the budget incorrectly, e.g. 0 or much bigger than heap size.
      +
      17902  if(m_Budget.m_VulkanBudget[heapIndex] == 0)
      +
      17903  {
      +
      17904  m_Budget.m_VulkanBudget[heapIndex] = m_MemProps.memoryHeaps[heapIndex].size * 8 / 10; // 80% heuristics.
      +
      17905  }
      +
      17906  else if(m_Budget.m_VulkanBudget[heapIndex] > m_MemProps.memoryHeaps[heapIndex].size)
      +
      17907  {
      +
      17908  m_Budget.m_VulkanBudget[heapIndex] = m_MemProps.memoryHeaps[heapIndex].size;
      +
      17909  }
      +
      17910  if(m_Budget.m_VulkanUsage[heapIndex] == 0 && m_Budget.m_BlockBytesAtBudgetFetch[heapIndex] > 0)
      +
      17911  {
      +
      17912  m_Budget.m_VulkanUsage[heapIndex] = m_Budget.m_BlockBytesAtBudgetFetch[heapIndex];
      +
      17913  }
      +
      17914  }
      +
      17915  m_Budget.m_OperationsSinceBudgetFetch = 0;
      +
      17916  }
      +
      17917 }
      +
      17918 
      +
      17919 #endif // #if VMA_MEMORY_BUDGET
      17920 
      -
      17921  if(stats.memoryHeap[heapIndex].blockCount > 0)
      -
      17922  {
      -
      17923  json.WriteString("Stats");
      -
      17924  VmaPrintStatInfo(json, stats.memoryHeap[heapIndex]);
      -
      17925  }
      -
      17926 
      -
      17927  for(uint32_t typeIndex = 0; typeIndex < allocator->GetMemoryTypeCount(); ++typeIndex)
      -
      17928  {
      -
      17929  if(allocator->MemoryTypeIndexToHeapIndex(typeIndex) == heapIndex)
      -
      17930  {
      -
      17931  json.BeginString("Type ");
      -
      17932  json.ContinueString(typeIndex);
      -
      17933  json.EndString();
      -
      17934 
      -
      17935  json.BeginObject();
      -
      17936 
      -
      17937  json.WriteString("Flags");
      -
      17938  json.BeginArray(true);
      -
      17939  VkMemoryPropertyFlags flags = allocator->m_MemProps.memoryTypes[typeIndex].propertyFlags;
      -
      17940  if((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0)
      -
      17941  {
      -
      17942  json.WriteString("DEVICE_LOCAL");
      -
      17943  }
      -
      17944  if((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
      -
      17945  {
      -
      17946  json.WriteString("HOST_VISIBLE");
      -
      17947  }
      -
      17948  if((flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0)
      -
      17949  {
      -
      17950  json.WriteString("HOST_COHERENT");
      -
      17951  }
      -
      17952  if((flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) != 0)
      -
      17953  {
      -
      17954  json.WriteString("HOST_CACHED");
      -
      17955  }
      -
      17956  if((flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) != 0)
      -
      17957  {
      -
      17958  json.WriteString("LAZILY_ALLOCATED");
      -
      17959  }
      -
      17960  if((flags & VK_MEMORY_PROPERTY_PROTECTED_BIT) != 0)
      -
      17961  {
      -
      17962  json.WriteString(" PROTECTED");
      -
      17963  }
      -
      17964  if((flags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY) != 0)
      -
      17965  {
      -
      17966  json.WriteString(" DEVICE_COHERENT");
      -
      17967  }
      -
      17968  if((flags & VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY) != 0)
      -
      17969  {
      -
      17970  json.WriteString(" DEVICE_UNCACHED");
      -
      17971  }
      -
      17972  json.EndArray();
      -
      17973 
      -
      17974  if(stats.memoryType[typeIndex].blockCount > 0)
      -
      17975  {
      -
      17976  json.WriteString("Stats");
      -
      17977  VmaPrintStatInfo(json, stats.memoryType[typeIndex]);
      -
      17978  }
      -
      17979 
      -
      17980  json.EndObject();
      -
      17981  }
      -
      17982  }
      -
      17983 
      -
      17984  json.EndObject();
      -
      17985  }
      -
      17986  if(detailedMap == VK_TRUE)
      -
      17987  {
      -
      17988  allocator->PrintDetailedMap(json);
      -
      17989  }
      -
      17990 
      -
      17991  json.EndObject();
      -
      17992  }
      -
      17993 
      -
      17994  const size_t len = sb.GetLength();
      -
      17995  char* const pChars = vma_new_array(allocator, char, len + 1);
      -
      17996  if(len > 0)
      -
      17997  {
      -
      17998  memcpy(pChars, sb.GetData(), len);
      -
      17999  }
      -
      18000  pChars[len] = '\0';
      -
      18001  *ppStatsString = pChars;
      -
      18002 }
      -
      18003 
      -
      18004 VMA_CALL_PRE void VMA_CALL_POST vmaFreeStatsString(
      -
      18005  VmaAllocator allocator,
      -
      18006  char* pStatsString)
      -
      18007 {
      -
      18008  if(pStatsString != VMA_NULL)
      -
      18009  {
      -
      18010  VMA_ASSERT(allocator);
      -
      18011  size_t len = strlen(pStatsString);
      -
      18012  vma_delete_array(allocator, pStatsString, len + 1);
      -
      18013  }
      -
      18014 }
      -
      18015 
      -
      18016 #endif // #if VMA_STATS_STRING_ENABLED
      -
      18017 
      -
      18018 /*
      -
      18019 This function is not protected by any mutex because it just reads immutable data.
      -
      18020 */
      -
      18021 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndex(
      -
      18022  VmaAllocator allocator,
      -
      18023  uint32_t memoryTypeBits,
      -
      18024  const VmaAllocationCreateInfo* pAllocationCreateInfo,
      -
      18025  uint32_t* pMemoryTypeIndex)
      -
      18026 {
      -
      18027  VMA_ASSERT(allocator != VK_NULL_HANDLE);
      -
      18028  VMA_ASSERT(pAllocationCreateInfo != VMA_NULL);
      -
      18029  VMA_ASSERT(pMemoryTypeIndex != VMA_NULL);
      -
      18030 
      -
      18031  memoryTypeBits &= allocator->GetGlobalMemoryTypeBits();
      -
      18032 
      -
      18033  if(pAllocationCreateInfo->memoryTypeBits != 0)
      -
      18034  {
      -
      18035  memoryTypeBits &= pAllocationCreateInfo->memoryTypeBits;
      +
      17921 void VmaAllocator_T::FillAllocation(const VmaAllocation hAllocation, uint8_t pattern)
      +
      17922 {
      +
      17923  if(VMA_DEBUG_INITIALIZE_ALLOCATIONS &&
      +
      17924  !hAllocation->CanBecomeLost() &&
      +
      17925  (m_MemProps.memoryTypes[hAllocation->GetMemoryTypeIndex()].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
      +
      17926  {
      +
      17927  void* pData = VMA_NULL;
      +
      17928  VkResult res = Map(hAllocation, &pData);
      +
      17929  if(res == VK_SUCCESS)
      +
      17930  {
      +
      17931  memset(pData, (int)pattern, (size_t)hAllocation->GetSize());
      +
      17932  FlushOrInvalidateAllocation(hAllocation, 0, VK_WHOLE_SIZE, VMA_CACHE_FLUSH);
      +
      17933  Unmap(hAllocation);
      +
      17934  }
      +
      17935  else
      +
      17936  {
      +
      17937  VMA_ASSERT(0 && "VMA_DEBUG_INITIALIZE_ALLOCATIONS is enabled, but couldn't map memory to fill allocation.");
      +
      17938  }
      +
      17939  }
      +
      17940 }
      +
      17941 
      +
      17942 uint32_t VmaAllocator_T::GetGpuDefragmentationMemoryTypeBits()
      +
      17943 {
      +
      17944  uint32_t memoryTypeBits = m_GpuDefragmentationMemoryTypeBits.load();
      +
      17945  if(memoryTypeBits == UINT32_MAX)
      +
      17946  {
      +
      17947  memoryTypeBits = CalculateGpuDefragmentationMemoryTypeBits();
      +
      17948  m_GpuDefragmentationMemoryTypeBits.store(memoryTypeBits);
      +
      17949  }
      +
      17950  return memoryTypeBits;
      +
      17951 }
      +
      17952 
      +
      17953 #if VMA_STATS_STRING_ENABLED
      +
      17954 
      +
      17955 void VmaAllocator_T::PrintDetailedMap(VmaJsonWriter& json)
      +
      17956 {
      +
      17957  bool dedicatedAllocationsStarted = false;
      +
      17958  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
      +
      17959  {
      +
      17960  VmaMutexLockRead dedicatedAllocationsLock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
      +
      17961  DedicatedAllocationLinkedList& dedicatedAllocList = m_DedicatedAllocations[memTypeIndex];
      +
      17962  if(!dedicatedAllocList.IsEmpty())
      +
      17963  {
      +
      17964  if(dedicatedAllocationsStarted == false)
      +
      17965  {
      +
      17966  dedicatedAllocationsStarted = true;
      +
      17967  json.WriteString("DedicatedAllocations");
      +
      17968  json.BeginObject();
      +
      17969  }
      +
      17970 
      +
      17971  json.BeginString("Type ");
      +
      17972  json.ContinueString(memTypeIndex);
      +
      17973  json.EndString();
      +
      17974 
      +
      17975  json.BeginArray();
      +
      17976 
      +
      17977  for(VmaAllocation alloc = dedicatedAllocList.Front();
      +
      17978  alloc != VMA_NULL; alloc = dedicatedAllocList.GetNext(alloc))
      +
      17979  {
      +
      17980  json.BeginObject(true);
      +
      17981  alloc->PrintParameters(json);
      +
      17982  json.EndObject();
      +
      17983  }
      +
      17984 
      +
      17985  json.EndArray();
      +
      17986  }
      +
      17987  }
      +
      17988  if(dedicatedAllocationsStarted)
      +
      17989  {
      +
      17990  json.EndObject();
      +
      17991  }
      +
      17992 
      +
      17993  {
      +
      17994  bool allocationsStarted = false;
      +
      17995  for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
      +
      17996  {
      +
      17997  if(m_pBlockVectors[memTypeIndex]->IsEmpty() == false)
      +
      17998  {
      +
      17999  if(allocationsStarted == false)
      +
      18000  {
      +
      18001  allocationsStarted = true;
      +
      18002  json.WriteString("DefaultPools");
      +
      18003  json.BeginObject();
      +
      18004  }
      +
      18005 
      +
      18006  json.BeginString("Type ");
      +
      18007  json.ContinueString(memTypeIndex);
      +
      18008  json.EndString();
      +
      18009 
      +
      18010  m_pBlockVectors[memTypeIndex]->PrintDetailedMap(json);
      +
      18011  }
      +
      18012  }
      +
      18013  if(allocationsStarted)
      +
      18014  {
      +
      18015  json.EndObject();
      +
      18016  }
      +
      18017  }
      +
      18018 
      +
      18019  // Custom pools
      +
      18020  {
      +
      18021  VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex);
      +
      18022  if(!m_Pools.IsEmpty())
      +
      18023  {
      +
      18024  json.WriteString("Pools");
      +
      18025  json.BeginObject();
      +
      18026  for(VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool))
      +
      18027  {
      +
      18028  json.BeginString();
      +
      18029  json.ContinueString(pool->GetId());
      +
      18030  json.EndString();
      +
      18031 
      +
      18032  pool->m_BlockVector.PrintDetailedMap(json);
      +
      18033  }
      +
      18034  json.EndObject();
      +
      18035  }
      18036  }
      -
      18037 
      -
      18038  uint32_t requiredFlags = pAllocationCreateInfo->requiredFlags;
      -
      18039  uint32_t preferredFlags = pAllocationCreateInfo->preferredFlags;
      -
      18040  uint32_t notPreferredFlags = 0;
      -
      18041 
      -
      18042  // Convert usage to requiredFlags and preferredFlags.
      -
      18043  switch(pAllocationCreateInfo->usage)
      -
      18044  {
      - -
      18046  break;
      - -
      18048  if(!allocator->IsIntegratedGpu() || (preferredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
      -
      18049  {
      -
      18050  preferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
      -
      18051  }
      -
      18052  break;
      - -
      18054  requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
      -
      18055  break;
      - -
      18057  requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
      -
      18058  if(!allocator->IsIntegratedGpu() || (preferredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
      -
      18059  {
      -
      18060  preferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
      -
      18061  }
      -
      18062  break;
      - -
      18064  requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
      -
      18065  preferredFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
      -
      18066  break;
      - -
      18068  notPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
      -
      18069  break;
      - -
      18071  requiredFlags |= VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT;
      -
      18072  break;
      -
      18073  default:
      -
      18074  VMA_ASSERT(0);
      -
      18075  break;
      -
      18076  }
      -
      18077 
      -
      18078  // Avoid DEVICE_COHERENT unless explicitly requested.
      -
      18079  if(((pAllocationCreateInfo->requiredFlags | pAllocationCreateInfo->preferredFlags) &
      -
      18080  (VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY | VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY)) == 0)
      -
      18081  {
      -
      18082  notPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY;
      -
      18083  }
      -
      18084 
      -
      18085  *pMemoryTypeIndex = UINT32_MAX;
      -
      18086  uint32_t minCost = UINT32_MAX;
      -
      18087  for(uint32_t memTypeIndex = 0, memTypeBit = 1;
      -
      18088  memTypeIndex < allocator->GetMemoryTypeCount();
      -
      18089  ++memTypeIndex, memTypeBit <<= 1)
      -
      18090  {
      -
      18091  // This memory type is acceptable according to memoryTypeBits bitmask.
      -
      18092  if((memTypeBit & memoryTypeBits) != 0)
      -
      18093  {
      -
      18094  const VkMemoryPropertyFlags currFlags =
      -
      18095  allocator->m_MemProps.memoryTypes[memTypeIndex].propertyFlags;
      -
      18096  // This memory type contains requiredFlags.
      -
      18097  if((requiredFlags & ~currFlags) == 0)
      -
      18098  {
      -
      18099  // Calculate cost as number of bits from preferredFlags not present in this memory type.
      -
      18100  uint32_t currCost = VmaCountBitsSet(preferredFlags & ~currFlags) +
      -
      18101  VmaCountBitsSet(currFlags & notPreferredFlags);
      -
      18102  // Remember memory type with lowest cost.
      -
      18103  if(currCost < minCost)
      -
      18104  {
      -
      18105  *pMemoryTypeIndex = memTypeIndex;
      -
      18106  if(currCost == 0)
      -
      18107  {
      -
      18108  return VK_SUCCESS;
      -
      18109  }
      -
      18110  minCost = currCost;
      -
      18111  }
      -
      18112  }
      -
      18113  }
      -
      18114  }
      -
      18115  return (*pMemoryTypeIndex != UINT32_MAX) ? VK_SUCCESS : VK_ERROR_FEATURE_NOT_PRESENT;
      -
      18116 }
      -
      18117 
      -
      18118 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForBufferInfo(
      -
      18119  VmaAllocator allocator,
      -
      18120  const VkBufferCreateInfo* pBufferCreateInfo,
      -
      18121  const VmaAllocationCreateInfo* pAllocationCreateInfo,
      -
      18122  uint32_t* pMemoryTypeIndex)
      -
      18123 {
      -
      18124  VMA_ASSERT(allocator != VK_NULL_HANDLE);
      -
      18125  VMA_ASSERT(pBufferCreateInfo != VMA_NULL);
      -
      18126  VMA_ASSERT(pAllocationCreateInfo != VMA_NULL);
      -
      18127  VMA_ASSERT(pMemoryTypeIndex != VMA_NULL);
      -
      18128 
      -
      18129  const VkDevice hDev = allocator->m_hDevice;
      -
      18130  VkBuffer hBuffer = VK_NULL_HANDLE;
      -
      18131  VkResult res = allocator->GetVulkanFunctions().vkCreateBuffer(
      -
      18132  hDev, pBufferCreateInfo, allocator->GetAllocationCallbacks(), &hBuffer);
      -
      18133  if(res == VK_SUCCESS)
      -
      18134  {
      -
      18135  VkMemoryRequirements memReq = {};
      -
      18136  allocator->GetVulkanFunctions().vkGetBufferMemoryRequirements(
      -
      18137  hDev, hBuffer, &memReq);
      -
      18138 
      -
      18139  res = vmaFindMemoryTypeIndex(
      -
      18140  allocator,
      -
      18141  memReq.memoryTypeBits,
      -
      18142  pAllocationCreateInfo,
      -
      18143  pMemoryTypeIndex);
      -
      18144 
      -
      18145  allocator->GetVulkanFunctions().vkDestroyBuffer(
      -
      18146  hDev, hBuffer, allocator->GetAllocationCallbacks());
      -
      18147  }
      -
      18148  return res;
      -
      18149 }
      -
      18150 
      -
      18151 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForImageInfo(
      -
      18152  VmaAllocator allocator,
      -
      18153  const VkImageCreateInfo* pImageCreateInfo,
      -
      18154  const VmaAllocationCreateInfo* pAllocationCreateInfo,
      -
      18155  uint32_t* pMemoryTypeIndex)
      -
      18156 {
      -
      18157  VMA_ASSERT(allocator != VK_NULL_HANDLE);
      -
      18158  VMA_ASSERT(pImageCreateInfo != VMA_NULL);
      -
      18159  VMA_ASSERT(pAllocationCreateInfo != VMA_NULL);
      -
      18160  VMA_ASSERT(pMemoryTypeIndex != VMA_NULL);
      +
      18037 }
      +
      18038 
      +
      18039 #endif // #if VMA_STATS_STRING_ENABLED
      +
      18040 
      +
      18042 // Public interface
      +
      18043 
      +
      18044 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator(
      +
      18045  const VmaAllocatorCreateInfo* pCreateInfo,
      +
      18046  VmaAllocator* pAllocator)
      +
      18047 {
      +
      18048  VMA_ASSERT(pCreateInfo && pAllocator);
      +
      18049  VMA_ASSERT(pCreateInfo->vulkanApiVersion == 0 ||
      +
      18050  (VK_VERSION_MAJOR(pCreateInfo->vulkanApiVersion) == 1 && VK_VERSION_MINOR(pCreateInfo->vulkanApiVersion) <= 2));
      +
      18051  VMA_DEBUG_LOG("vmaCreateAllocator");
      +
      18052  *pAllocator = vma_new(pCreateInfo->pAllocationCallbacks, VmaAllocator_T)(pCreateInfo);
      +
      18053  return (*pAllocator)->Init(pCreateInfo);
      +
      18054 }
      +
      18055 
      +
      18056 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyAllocator(
      +
      18057  VmaAllocator allocator)
      +
      18058 {
      +
      18059  if(allocator != VK_NULL_HANDLE)
      +
      18060  {
      +
      18061  VMA_DEBUG_LOG("vmaDestroyAllocator");
      +
      18062  VkAllocationCallbacks allocationCallbacks = allocator->m_AllocationCallbacks;
      +
      18063  vma_delete(&allocationCallbacks, allocator);
      +
      18064  }
      +
      18065 }
      +
      18066 
      +
      18067 VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocatorInfo(VmaAllocator allocator, VmaAllocatorInfo* pAllocatorInfo)
      +
      18068 {
      +
      18069  VMA_ASSERT(allocator && pAllocatorInfo);
      +
      18070  pAllocatorInfo->instance = allocator->m_hInstance;
      +
      18071  pAllocatorInfo->physicalDevice = allocator->GetPhysicalDevice();
      +
      18072  pAllocatorInfo->device = allocator->m_hDevice;
      +
      18073 }
      +
      18074 
      +
      18075 VMA_CALL_PRE void VMA_CALL_POST vmaGetPhysicalDeviceProperties(
      +
      18076  VmaAllocator allocator,
      +
      18077  const VkPhysicalDeviceProperties **ppPhysicalDeviceProperties)
      +
      18078 {
      +
      18079  VMA_ASSERT(allocator && ppPhysicalDeviceProperties);
      +
      18080  *ppPhysicalDeviceProperties = &allocator->m_PhysicalDeviceProperties;
      +
      18081 }
      +
      18082 
      +
      18083 VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryProperties(
      +
      18084  VmaAllocator allocator,
      +
      18085  const VkPhysicalDeviceMemoryProperties** ppPhysicalDeviceMemoryProperties)
      +
      18086 {
      +
      18087  VMA_ASSERT(allocator && ppPhysicalDeviceMemoryProperties);
      +
      18088  *ppPhysicalDeviceMemoryProperties = &allocator->m_MemProps;
      +
      18089 }
      +
      18090 
      +
      18091 VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryTypeProperties(
      +
      18092  VmaAllocator allocator,
      +
      18093  uint32_t memoryTypeIndex,
      +
      18094  VkMemoryPropertyFlags* pFlags)
      +
      18095 {
      +
      18096  VMA_ASSERT(allocator && pFlags);
      +
      18097  VMA_ASSERT(memoryTypeIndex < allocator->GetMemoryTypeCount());
      +
      18098  *pFlags = allocator->m_MemProps.memoryTypes[memoryTypeIndex].propertyFlags;
      +
      18099 }
      +
      18100 
      +
      18101 VMA_CALL_PRE void VMA_CALL_POST vmaSetCurrentFrameIndex(
      +
      18102  VmaAllocator allocator,
      +
      18103  uint32_t frameIndex)
      +
      18104 {
      +
      18105  VMA_ASSERT(allocator);
      +
      18106  VMA_ASSERT(frameIndex != VMA_FRAME_INDEX_LOST);
      +
      18107 
      +
      18108  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18109 
      +
      18110  allocator->SetCurrentFrameIndex(frameIndex);
      +
      18111 }
      +
      18112 
      +
      18113 VMA_CALL_PRE void VMA_CALL_POST vmaCalculateStats(
      +
      18114  VmaAllocator allocator,
      +
      18115  VmaStats* pStats)
      +
      18116 {
      +
      18117  VMA_ASSERT(allocator && pStats);
      +
      18118  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18119  allocator->CalculateStats(pStats);
      +
      18120 }
      +
      18121 
      +
      18122 VMA_CALL_PRE void VMA_CALL_POST vmaGetBudget(
      +
      18123  VmaAllocator allocator,
      +
      18124  VmaBudget* pBudget)
      +
      18125 {
      +
      18126  VMA_ASSERT(allocator && pBudget);
      +
      18127  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18128  allocator->GetBudget(pBudget, 0, allocator->GetMemoryHeapCount());
      +
      18129 }
      +
      18130 
      +
      18131 #if VMA_STATS_STRING_ENABLED
      +
      18132 
      +
      18133 VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString(
      +
      18134  VmaAllocator allocator,
      +
      18135  char** ppStatsString,
      +
      18136  VkBool32 detailedMap)
      +
      18137 {
      +
      18138  VMA_ASSERT(allocator && ppStatsString);
      +
      18139  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18140 
      +
      18141  VmaStringBuilder sb(allocator);
      +
      18142  {
      +
      18143  VmaJsonWriter json(allocator->GetAllocationCallbacks(), sb);
      +
      18144  json.BeginObject();
      +
      18145 
      +
      18146  VmaBudget budget[VK_MAX_MEMORY_HEAPS];
      +
      18147  allocator->GetBudget(budget, 0, allocator->GetMemoryHeapCount());
      +
      18148 
      +
      18149  VmaStats stats;
      +
      18150  allocator->CalculateStats(&stats);
      +
      18151 
      +
      18152  json.WriteString("Total");
      +
      18153  VmaPrintStatInfo(json, stats.total);
      +
      18154 
      +
      18155  for(uint32_t heapIndex = 0; heapIndex < allocator->GetMemoryHeapCount(); ++heapIndex)
      +
      18156  {
      +
      18157  json.BeginString("Heap ");
      +
      18158  json.ContinueString(heapIndex);
      +
      18159  json.EndString();
      +
      18160  json.BeginObject();
      18161 
      -
      18162  const VkDevice hDev = allocator->m_hDevice;
      -
      18163  VkImage hImage = VK_NULL_HANDLE;
      -
      18164  VkResult res = allocator->GetVulkanFunctions().vkCreateImage(
      -
      18165  hDev, pImageCreateInfo, allocator->GetAllocationCallbacks(), &hImage);
      -
      18166  if(res == VK_SUCCESS)
      -
      18167  {
      -
      18168  VkMemoryRequirements memReq = {};
      -
      18169  allocator->GetVulkanFunctions().vkGetImageMemoryRequirements(
      -
      18170  hDev, hImage, &memReq);
      -
      18171 
      -
      18172  res = vmaFindMemoryTypeIndex(
      -
      18173  allocator,
      -
      18174  memReq.memoryTypeBits,
      -
      18175  pAllocationCreateInfo,
      -
      18176  pMemoryTypeIndex);
      -
      18177 
      -
      18178  allocator->GetVulkanFunctions().vkDestroyImage(
      -
      18179  hDev, hImage, allocator->GetAllocationCallbacks());
      -
      18180  }
      -
      18181  return res;
      -
      18182 }
      -
      18183 
      -
      18184 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreatePool(
      -
      18185  VmaAllocator allocator,
      -
      18186  const VmaPoolCreateInfo* pCreateInfo,
      -
      18187  VmaPool* pPool)
      -
      18188 {
      -
      18189  VMA_ASSERT(allocator && pCreateInfo && pPool);
      -
      18190 
      -
      18191  VMA_DEBUG_LOG("vmaCreatePool");
      +
      18162  json.WriteString("Size");
      +
      18163  json.WriteNumber(allocator->m_MemProps.memoryHeaps[heapIndex].size);
      +
      18164 
      +
      18165  json.WriteString("Flags");
      +
      18166  json.BeginArray(true);
      +
      18167  if((allocator->m_MemProps.memoryHeaps[heapIndex].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0)
      +
      18168  {
      +
      18169  json.WriteString("DEVICE_LOCAL");
      +
      18170  }
      +
      18171  json.EndArray();
      +
      18172 
      +
      18173  json.WriteString("Budget");
      +
      18174  json.BeginObject();
      +
      18175  {
      +
      18176  json.WriteString("BlockBytes");
      +
      18177  json.WriteNumber(budget[heapIndex].blockBytes);
      +
      18178  json.WriteString("AllocationBytes");
      +
      18179  json.WriteNumber(budget[heapIndex].allocationBytes);
      +
      18180  json.WriteString("Usage");
      +
      18181  json.WriteNumber(budget[heapIndex].usage);
      +
      18182  json.WriteString("Budget");
      +
      18183  json.WriteNumber(budget[heapIndex].budget);
      +
      18184  }
      +
      18185  json.EndObject();
      +
      18186 
      +
      18187  if(stats.memoryHeap[heapIndex].blockCount > 0)
      +
      18188  {
      +
      18189  json.WriteString("Stats");
      +
      18190  VmaPrintStatInfo(json, stats.memoryHeap[heapIndex]);
      +
      18191  }
      18192 
      -
      18193  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18194 
      -
      18195  VkResult res = allocator->CreatePool(pCreateInfo, pPool);
      -
      18196 
      -
      18197 #if VMA_RECORDING_ENABLED
      -
      18198  if(allocator->GetRecorder() != VMA_NULL)
      -
      18199  {
      -
      18200  allocator->GetRecorder()->RecordCreatePool(allocator->GetCurrentFrameIndex(), *pCreateInfo, *pPool);
      -
      18201  }
      -
      18202 #endif
      -
      18203 
      -
      18204  return res;
      -
      18205 }
      -
      18206 
      -
      18207 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyPool(
      -
      18208  VmaAllocator allocator,
      -
      18209  VmaPool pool)
      -
      18210 {
      -
      18211  VMA_ASSERT(allocator);
      -
      18212 
      -
      18213  if(pool == VK_NULL_HANDLE)
      -
      18214  {
      -
      18215  return;
      -
      18216  }
      -
      18217 
      -
      18218  VMA_DEBUG_LOG("vmaDestroyPool");
      -
      18219 
      -
      18220  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18221 
      -
      18222 #if VMA_RECORDING_ENABLED
      -
      18223  if(allocator->GetRecorder() != VMA_NULL)
      -
      18224  {
      -
      18225  allocator->GetRecorder()->RecordDestroyPool(allocator->GetCurrentFrameIndex(), pool);
      -
      18226  }
      -
      18227 #endif
      -
      18228 
      -
      18229  allocator->DestroyPool(pool);
      -
      18230 }
      -
      18231 
      -
      18232 VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolStats(
      -
      18233  VmaAllocator allocator,
      -
      18234  VmaPool pool,
      -
      18235  VmaPoolStats* pPoolStats)
      -
      18236 {
      -
      18237  VMA_ASSERT(allocator && pool && pPoolStats);
      -
      18238 
      -
      18239  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18240 
      -
      18241  allocator->GetPoolStats(pool, pPoolStats);
      -
      18242 }
      +
      18193  for(uint32_t typeIndex = 0; typeIndex < allocator->GetMemoryTypeCount(); ++typeIndex)
      +
      18194  {
      +
      18195  if(allocator->MemoryTypeIndexToHeapIndex(typeIndex) == heapIndex)
      +
      18196  {
      +
      18197  json.BeginString("Type ");
      +
      18198  json.ContinueString(typeIndex);
      +
      18199  json.EndString();
      +
      18200 
      +
      18201  json.BeginObject();
      +
      18202 
      +
      18203  json.WriteString("Flags");
      +
      18204  json.BeginArray(true);
      +
      18205  VkMemoryPropertyFlags flags = allocator->m_MemProps.memoryTypes[typeIndex].propertyFlags;
      +
      18206  if((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0)
      +
      18207  {
      +
      18208  json.WriteString("DEVICE_LOCAL");
      +
      18209  }
      +
      18210  if((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
      +
      18211  {
      +
      18212  json.WriteString("HOST_VISIBLE");
      +
      18213  }
      +
      18214  if((flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0)
      +
      18215  {
      +
      18216  json.WriteString("HOST_COHERENT");
      +
      18217  }
      +
      18218  if((flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) != 0)
      +
      18219  {
      +
      18220  json.WriteString("HOST_CACHED");
      +
      18221  }
      +
      18222  if((flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) != 0)
      +
      18223  {
      +
      18224  json.WriteString("LAZILY_ALLOCATED");
      +
      18225  }
      +
      18226 #if VMA_VULKAN_VERSION >= 1001000
      +
      18227  if((flags & VK_MEMORY_PROPERTY_PROTECTED_BIT) != 0)
      +
      18228  {
      +
      18229  json.WriteString("PROTECTED");
      +
      18230  }
      +
      18231 #endif // #if VMA_VULKAN_VERSION >= 1001000
      +
      18232 #if VK_AMD_device_coherent_memory
      +
      18233  if((flags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY) != 0)
      +
      18234  {
      +
      18235  json.WriteString("DEVICE_COHERENT");
      +
      18236  }
      +
      18237  if((flags & VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY) != 0)
      +
      18238  {
      +
      18239  json.WriteString("DEVICE_UNCACHED");
      +
      18240  }
      +
      18241 #endif // #if VK_AMD_device_coherent_memory
      +
      18242  json.EndArray();
      18243 
      -
      18244 VMA_CALL_PRE void VMA_CALL_POST vmaMakePoolAllocationsLost(
      -
      18245  VmaAllocator allocator,
      -
      18246  VmaPool pool,
      -
      18247  size_t* pLostAllocationCount)
      -
      18248 {
      -
      18249  VMA_ASSERT(allocator && pool);
      -
      18250 
      -
      18251  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18252 
      -
      18253 #if VMA_RECORDING_ENABLED
      -
      18254  if(allocator->GetRecorder() != VMA_NULL)
      -
      18255  {
      -
      18256  allocator->GetRecorder()->RecordMakePoolAllocationsLost(allocator->GetCurrentFrameIndex(), pool);
      -
      18257  }
      -
      18258 #endif
      -
      18259 
      -
      18260  allocator->MakePoolAllocationsLost(pool, pLostAllocationCount);
      -
      18261 }
      -
      18262 
      -
      18263 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckPoolCorruption(VmaAllocator allocator, VmaPool pool)
      -
      18264 {
      -
      18265  VMA_ASSERT(allocator && pool);
      -
      18266 
      -
      18267  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18268 
      -
      18269  VMA_DEBUG_LOG("vmaCheckPoolCorruption");
      -
      18270 
      -
      18271  return allocator->CheckPoolCorruption(pool);
      +
      18244  if(stats.memoryType[typeIndex].blockCount > 0)
      +
      18245  {
      +
      18246  json.WriteString("Stats");
      +
      18247  VmaPrintStatInfo(json, stats.memoryType[typeIndex]);
      +
      18248  }
      +
      18249 
      +
      18250  json.EndObject();
      +
      18251  }
      +
      18252  }
      +
      18253 
      +
      18254  json.EndObject();
      +
      18255  }
      +
      18256  if(detailedMap == VK_TRUE)
      +
      18257  {
      +
      18258  allocator->PrintDetailedMap(json);
      +
      18259  }
      +
      18260 
      +
      18261  json.EndObject();
      +
      18262  }
      +
      18263 
      +
      18264  const size_t len = sb.GetLength();
      +
      18265  char* const pChars = vma_new_array(allocator, char, len + 1);
      +
      18266  if(len > 0)
      +
      18267  {
      +
      18268  memcpy(pChars, sb.GetData(), len);
      +
      18269  }
      +
      18270  pChars[len] = '\0';
      +
      18271  *ppStatsString = pChars;
      18272 }
      18273 
      -
      18274 VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolName(
      +
      18274 VMA_CALL_PRE void VMA_CALL_POST vmaFreeStatsString(
      18275  VmaAllocator allocator,
      -
      18276  VmaPool pool,
      -
      18277  const char** ppName)
      -
      18278 {
      -
      18279  VMA_ASSERT(allocator && pool && ppName);
      -
      18280 
      -
      18281  VMA_DEBUG_LOG("vmaGetPoolName");
      -
      18282 
      -
      18283  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18284 
      -
      18285  *ppName = pool->GetName();
      -
      18286 }
      +
      18276  char* pStatsString)
      +
      18277 {
      +
      18278  if(pStatsString != VMA_NULL)
      +
      18279  {
      +
      18280  VMA_ASSERT(allocator);
      +
      18281  size_t len = strlen(pStatsString);
      +
      18282  vma_delete_array(allocator, pStatsString, len + 1);
      +
      18283  }
      +
      18284 }
      +
      18285 
      +
      18286 #endif // #if VMA_STATS_STRING_ENABLED
      18287 
      -
      18288 VMA_CALL_PRE void VMA_CALL_POST vmaSetPoolName(
      -
      18289  VmaAllocator allocator,
      -
      18290  VmaPool pool,
      -
      18291  const char* pName)
      -
      18292 {
      -
      18293  VMA_ASSERT(allocator && pool);
      -
      18294 
      -
      18295  VMA_DEBUG_LOG("vmaSetPoolName");
      -
      18296 
      -
      18297  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18298 
      -
      18299  pool->SetName(pName);
      +
      18288 /*
      +
      18289 This function is not protected by any mutex because it just reads immutable data.
      +
      18290 */
      +
      18291 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndex(
      +
      18292  VmaAllocator allocator,
      +
      18293  uint32_t memoryTypeBits,
      +
      18294  const VmaAllocationCreateInfo* pAllocationCreateInfo,
      +
      18295  uint32_t* pMemoryTypeIndex)
      +
      18296 {
      +
      18297  VMA_ASSERT(allocator != VK_NULL_HANDLE);
      +
      18298  VMA_ASSERT(pAllocationCreateInfo != VMA_NULL);
      +
      18299  VMA_ASSERT(pMemoryTypeIndex != VMA_NULL);
      18300 
      -
      18301 #if VMA_RECORDING_ENABLED
      -
      18302  if(allocator->GetRecorder() != VMA_NULL)
      -
      18303  {
      -
      18304  allocator->GetRecorder()->RecordSetPoolName(allocator->GetCurrentFrameIndex(), pool, pName);
      -
      18305  }
      -
      18306 #endif
      -
      18307 }
      -
      18308 
      -
      18309 VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemory(
      -
      18310  VmaAllocator allocator,
      -
      18311  const VkMemoryRequirements* pVkMemoryRequirements,
      -
      18312  const VmaAllocationCreateInfo* pCreateInfo,
      -
      18313  VmaAllocation* pAllocation,
      -
      18314  VmaAllocationInfo* pAllocationInfo)
      -
      18315 {
      -
      18316  VMA_ASSERT(allocator && pVkMemoryRequirements && pCreateInfo && pAllocation);
      -
      18317 
      -
      18318  VMA_DEBUG_LOG("vmaAllocateMemory");
      -
      18319 
      -
      18320  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18321 
      -
      18322  VkResult result = allocator->AllocateMemory(
      -
      18323  *pVkMemoryRequirements,
      -
      18324  false, // requiresDedicatedAllocation
      -
      18325  false, // prefersDedicatedAllocation
      -
      18326  VK_NULL_HANDLE, // dedicatedBuffer
      -
      18327  UINT32_MAX, // dedicatedBufferUsage
      -
      18328  VK_NULL_HANDLE, // dedicatedImage
      -
      18329  *pCreateInfo,
      -
      18330  VMA_SUBALLOCATION_TYPE_UNKNOWN,
      -
      18331  1, // allocationCount
      -
      18332  pAllocation);
      -
      18333 
      -
      18334 #if VMA_RECORDING_ENABLED
      -
      18335  if(allocator->GetRecorder() != VMA_NULL)
      -
      18336  {
      -
      18337  allocator->GetRecorder()->RecordAllocateMemory(
      -
      18338  allocator->GetCurrentFrameIndex(),
      -
      18339  *pVkMemoryRequirements,
      -
      18340  *pCreateInfo,
      -
      18341  *pAllocation);
      -
      18342  }
      -
      18343 #endif
      -
      18344 
      -
      18345  if(pAllocationInfo != VMA_NULL && result == VK_SUCCESS)
      -
      18346  {
      -
      18347  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
      -
      18348  }
      -
      18349 
      -
      18350  return result;
      -
      18351 }
      -
      18352 
      -
      18353 VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryPages(
      -
      18354  VmaAllocator allocator,
      -
      18355  const VkMemoryRequirements* pVkMemoryRequirements,
      -
      18356  const VmaAllocationCreateInfo* pCreateInfo,
      -
      18357  size_t allocationCount,
      -
      18358  VmaAllocation* pAllocations,
      -
      18359  VmaAllocationInfo* pAllocationInfo)
      -
      18360 {
      -
      18361  if(allocationCount == 0)
      -
      18362  {
      -
      18363  return VK_SUCCESS;
      -
      18364  }
      -
      18365 
      -
      18366  VMA_ASSERT(allocator && pVkMemoryRequirements && pCreateInfo && pAllocations);
      -
      18367 
      -
      18368  VMA_DEBUG_LOG("vmaAllocateMemoryPages");
      -
      18369 
      -
      18370  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18371 
      -
      18372  VkResult result = allocator->AllocateMemory(
      -
      18373  *pVkMemoryRequirements,
      -
      18374  false, // requiresDedicatedAllocation
      -
      18375  false, // prefersDedicatedAllocation
      -
      18376  VK_NULL_HANDLE, // dedicatedBuffer
      -
      18377  UINT32_MAX, // dedicatedBufferUsage
      -
      18378  VK_NULL_HANDLE, // dedicatedImage
      -
      18379  *pCreateInfo,
      -
      18380  VMA_SUBALLOCATION_TYPE_UNKNOWN,
      -
      18381  allocationCount,
      -
      18382  pAllocations);
      -
      18383 
      -
      18384 #if VMA_RECORDING_ENABLED
      -
      18385  if(allocator->GetRecorder() != VMA_NULL)
      -
      18386  {
      -
      18387  allocator->GetRecorder()->RecordAllocateMemoryPages(
      -
      18388  allocator->GetCurrentFrameIndex(),
      -
      18389  *pVkMemoryRequirements,
      -
      18390  *pCreateInfo,
      -
      18391  (uint64_t)allocationCount,
      -
      18392  pAllocations);
      -
      18393  }
      -
      18394 #endif
      -
      18395 
      -
      18396  if(pAllocationInfo != VMA_NULL && result == VK_SUCCESS)
      -
      18397  {
      -
      18398  for(size_t i = 0; i < allocationCount; ++i)
      -
      18399  {
      -
      18400  allocator->GetAllocationInfo(pAllocations[i], pAllocationInfo + i);
      -
      18401  }
      -
      18402  }
      -
      18403 
      -
      18404  return result;
      -
      18405 }
      -
      18406 
      -
      18407 VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForBuffer(
      -
      18408  VmaAllocator allocator,
      -
      18409  VkBuffer buffer,
      -
      18410  const VmaAllocationCreateInfo* pCreateInfo,
      -
      18411  VmaAllocation* pAllocation,
      -
      18412  VmaAllocationInfo* pAllocationInfo)
      -
      18413 {
      -
      18414  VMA_ASSERT(allocator && buffer != VK_NULL_HANDLE && pCreateInfo && pAllocation);
      -
      18415 
      -
      18416  VMA_DEBUG_LOG("vmaAllocateMemoryForBuffer");
      -
      18417 
      -
      18418  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18419 
      -
      18420  VkMemoryRequirements vkMemReq = {};
      -
      18421  bool requiresDedicatedAllocation = false;
      -
      18422  bool prefersDedicatedAllocation = false;
      -
      18423  allocator->GetBufferMemoryRequirements(buffer, vkMemReq,
      -
      18424  requiresDedicatedAllocation,
      -
      18425  prefersDedicatedAllocation);
      -
      18426 
      -
      18427  VkResult result = allocator->AllocateMemory(
      -
      18428  vkMemReq,
      -
      18429  requiresDedicatedAllocation,
      -
      18430  prefersDedicatedAllocation,
      -
      18431  buffer, // dedicatedBuffer
      -
      18432  UINT32_MAX, // dedicatedBufferUsage
      -
      18433  VK_NULL_HANDLE, // dedicatedImage
      -
      18434  *pCreateInfo,
      -
      18435  VMA_SUBALLOCATION_TYPE_BUFFER,
      -
      18436  1, // allocationCount
      -
      18437  pAllocation);
      -
      18438 
      -
      18439 #if VMA_RECORDING_ENABLED
      -
      18440  if(allocator->GetRecorder() != VMA_NULL)
      -
      18441  {
      -
      18442  allocator->GetRecorder()->RecordAllocateMemoryForBuffer(
      -
      18443  allocator->GetCurrentFrameIndex(),
      -
      18444  vkMemReq,
      -
      18445  requiresDedicatedAllocation,
      -
      18446  prefersDedicatedAllocation,
      -
      18447  *pCreateInfo,
      -
      18448  *pAllocation);
      -
      18449  }
      -
      18450 #endif
      -
      18451 
      -
      18452  if(pAllocationInfo && result == VK_SUCCESS)
      -
      18453  {
      -
      18454  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
      -
      18455  }
      -
      18456 
      -
      18457  return result;
      -
      18458 }
      -
      18459 
      -
      18460 VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForImage(
      -
      18461  VmaAllocator allocator,
      -
      18462  VkImage image,
      -
      18463  const VmaAllocationCreateInfo* pCreateInfo,
      -
      18464  VmaAllocation* pAllocation,
      -
      18465  VmaAllocationInfo* pAllocationInfo)
      -
      18466 {
      -
      18467  VMA_ASSERT(allocator && image != VK_NULL_HANDLE && pCreateInfo && pAllocation);
      -
      18468 
      -
      18469  VMA_DEBUG_LOG("vmaAllocateMemoryForImage");
      -
      18470 
      -
      18471  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18472 
      -
      18473  VkMemoryRequirements vkMemReq = {};
      -
      18474  bool requiresDedicatedAllocation = false;
      -
      18475  bool prefersDedicatedAllocation = false;
      -
      18476  allocator->GetImageMemoryRequirements(image, vkMemReq,
      -
      18477  requiresDedicatedAllocation, prefersDedicatedAllocation);
      -
      18478 
      -
      18479  VkResult result = allocator->AllocateMemory(
      -
      18480  vkMemReq,
      -
      18481  requiresDedicatedAllocation,
      -
      18482  prefersDedicatedAllocation,
      -
      18483  VK_NULL_HANDLE, // dedicatedBuffer
      -
      18484  UINT32_MAX, // dedicatedBufferUsage
      -
      18485  image, // dedicatedImage
      -
      18486  *pCreateInfo,
      -
      18487  VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN,
      -
      18488  1, // allocationCount
      -
      18489  pAllocation);
      -
      18490 
      -
      18491 #if VMA_RECORDING_ENABLED
      -
      18492  if(allocator->GetRecorder() != VMA_NULL)
      -
      18493  {
      -
      18494  allocator->GetRecorder()->RecordAllocateMemoryForImage(
      -
      18495  allocator->GetCurrentFrameIndex(),
      -
      18496  vkMemReq,
      -
      18497  requiresDedicatedAllocation,
      -
      18498  prefersDedicatedAllocation,
      -
      18499  *pCreateInfo,
      -
      18500  *pAllocation);
      -
      18501  }
      -
      18502 #endif
      -
      18503 
      -
      18504  if(pAllocationInfo && result == VK_SUCCESS)
      -
      18505  {
      -
      18506  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
      -
      18507  }
      +
      18301  memoryTypeBits &= allocator->GetGlobalMemoryTypeBits();
      +
      18302 
      +
      18303  if(pAllocationCreateInfo->memoryTypeBits != 0)
      +
      18304  {
      +
      18305  memoryTypeBits &= pAllocationCreateInfo->memoryTypeBits;
      +
      18306  }
      +
      18307 
      +
      18308  uint32_t requiredFlags = pAllocationCreateInfo->requiredFlags;
      +
      18309  uint32_t preferredFlags = pAllocationCreateInfo->preferredFlags;
      +
      18310  uint32_t notPreferredFlags = 0;
      +
      18311 
      +
      18312  // Convert usage to requiredFlags and preferredFlags.
      +
      18313  switch(pAllocationCreateInfo->usage)
      +
      18314  {
      + +
      18316  break;
      + +
      18318  if(!allocator->IsIntegratedGpu() || (preferredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
      +
      18319  {
      +
      18320  preferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
      +
      18321  }
      +
      18322  break;
      + +
      18324  requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
      +
      18325  break;
      + +
      18327  requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
      +
      18328  if(!allocator->IsIntegratedGpu() || (preferredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
      +
      18329  {
      +
      18330  preferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
      +
      18331  }
      +
      18332  break;
      + +
      18334  requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
      +
      18335  preferredFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
      +
      18336  break;
      + +
      18338  notPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
      +
      18339  break;
      + +
      18341  requiredFlags |= VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT;
      +
      18342  break;
      +
      18343  default:
      +
      18344  VMA_ASSERT(0);
      +
      18345  break;
      +
      18346  }
      +
      18347 
      +
      18348  // Avoid DEVICE_COHERENT unless explicitly requested.
      +
      18349  if(((pAllocationCreateInfo->requiredFlags | pAllocationCreateInfo->preferredFlags) &
      +
      18350  (VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY | VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY)) == 0)
      +
      18351  {
      +
      18352  notPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY;
      +
      18353  }
      +
      18354 
      +
      18355  *pMemoryTypeIndex = UINT32_MAX;
      +
      18356  uint32_t minCost = UINT32_MAX;
      +
      18357  for(uint32_t memTypeIndex = 0, memTypeBit = 1;
      +
      18358  memTypeIndex < allocator->GetMemoryTypeCount();
      +
      18359  ++memTypeIndex, memTypeBit <<= 1)
      +
      18360  {
      +
      18361  // This memory type is acceptable according to memoryTypeBits bitmask.
      +
      18362  if((memTypeBit & memoryTypeBits) != 0)
      +
      18363  {
      +
      18364  const VkMemoryPropertyFlags currFlags =
      +
      18365  allocator->m_MemProps.memoryTypes[memTypeIndex].propertyFlags;
      +
      18366  // This memory type contains requiredFlags.
      +
      18367  if((requiredFlags & ~currFlags) == 0)
      +
      18368  {
      +
      18369  // Calculate cost as number of bits from preferredFlags not present in this memory type.
      +
      18370  uint32_t currCost = VmaCountBitsSet(preferredFlags & ~currFlags) +
      +
      18371  VmaCountBitsSet(currFlags & notPreferredFlags);
      +
      18372  // Remember memory type with lowest cost.
      +
      18373  if(currCost < minCost)
      +
      18374  {
      +
      18375  *pMemoryTypeIndex = memTypeIndex;
      +
      18376  if(currCost == 0)
      +
      18377  {
      +
      18378  return VK_SUCCESS;
      +
      18379  }
      +
      18380  minCost = currCost;
      +
      18381  }
      +
      18382  }
      +
      18383  }
      +
      18384  }
      +
      18385  return (*pMemoryTypeIndex != UINT32_MAX) ? VK_SUCCESS : VK_ERROR_FEATURE_NOT_PRESENT;
      +
      18386 }
      +
      18387 
      +
      18388 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForBufferInfo(
      +
      18389  VmaAllocator allocator,
      +
      18390  const VkBufferCreateInfo* pBufferCreateInfo,
      +
      18391  const VmaAllocationCreateInfo* pAllocationCreateInfo,
      +
      18392  uint32_t* pMemoryTypeIndex)
      +
      18393 {
      +
      18394  VMA_ASSERT(allocator != VK_NULL_HANDLE);
      +
      18395  VMA_ASSERT(pBufferCreateInfo != VMA_NULL);
      +
      18396  VMA_ASSERT(pAllocationCreateInfo != VMA_NULL);
      +
      18397  VMA_ASSERT(pMemoryTypeIndex != VMA_NULL);
      +
      18398 
      +
      18399  const VkDevice hDev = allocator->m_hDevice;
      +
      18400  VkBuffer hBuffer = VK_NULL_HANDLE;
      +
      18401  VkResult res = allocator->GetVulkanFunctions().vkCreateBuffer(
      +
      18402  hDev, pBufferCreateInfo, allocator->GetAllocationCallbacks(), &hBuffer);
      +
      18403  if(res == VK_SUCCESS)
      +
      18404  {
      +
      18405  VkMemoryRequirements memReq = {};
      +
      18406  allocator->GetVulkanFunctions().vkGetBufferMemoryRequirements(
      +
      18407  hDev, hBuffer, &memReq);
      +
      18408 
      +
      18409  res = vmaFindMemoryTypeIndex(
      +
      18410  allocator,
      +
      18411  memReq.memoryTypeBits,
      +
      18412  pAllocationCreateInfo,
      +
      18413  pMemoryTypeIndex);
      +
      18414 
      +
      18415  allocator->GetVulkanFunctions().vkDestroyBuffer(
      +
      18416  hDev, hBuffer, allocator->GetAllocationCallbacks());
      +
      18417  }
      +
      18418  return res;
      +
      18419 }
      +
      18420 
      +
      18421 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForImageInfo(
      +
      18422  VmaAllocator allocator,
      +
      18423  const VkImageCreateInfo* pImageCreateInfo,
      +
      18424  const VmaAllocationCreateInfo* pAllocationCreateInfo,
      +
      18425  uint32_t* pMemoryTypeIndex)
      +
      18426 {
      +
      18427  VMA_ASSERT(allocator != VK_NULL_HANDLE);
      +
      18428  VMA_ASSERT(pImageCreateInfo != VMA_NULL);
      +
      18429  VMA_ASSERT(pAllocationCreateInfo != VMA_NULL);
      +
      18430  VMA_ASSERT(pMemoryTypeIndex != VMA_NULL);
      +
      18431 
      +
      18432  const VkDevice hDev = allocator->m_hDevice;
      +
      18433  VkImage hImage = VK_NULL_HANDLE;
      +
      18434  VkResult res = allocator->GetVulkanFunctions().vkCreateImage(
      +
      18435  hDev, pImageCreateInfo, allocator->GetAllocationCallbacks(), &hImage);
      +
      18436  if(res == VK_SUCCESS)
      +
      18437  {
      +
      18438  VkMemoryRequirements memReq = {};
      +
      18439  allocator->GetVulkanFunctions().vkGetImageMemoryRequirements(
      +
      18440  hDev, hImage, &memReq);
      +
      18441 
      +
      18442  res = vmaFindMemoryTypeIndex(
      +
      18443  allocator,
      +
      18444  memReq.memoryTypeBits,
      +
      18445  pAllocationCreateInfo,
      +
      18446  pMemoryTypeIndex);
      +
      18447 
      +
      18448  allocator->GetVulkanFunctions().vkDestroyImage(
      +
      18449  hDev, hImage, allocator->GetAllocationCallbacks());
      +
      18450  }
      +
      18451  return res;
      +
      18452 }
      +
      18453 
      +
      18454 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreatePool(
      +
      18455  VmaAllocator allocator,
      +
      18456  const VmaPoolCreateInfo* pCreateInfo,
      +
      18457  VmaPool* pPool)
      +
      18458 {
      +
      18459  VMA_ASSERT(allocator && pCreateInfo && pPool);
      +
      18460 
      +
      18461  VMA_DEBUG_LOG("vmaCreatePool");
      +
      18462 
      +
      18463  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18464 
      +
      18465  VkResult res = allocator->CreatePool(pCreateInfo, pPool);
      +
      18466 
      +
      18467 #if VMA_RECORDING_ENABLED
      +
      18468  if(allocator->GetRecorder() != VMA_NULL)
      +
      18469  {
      +
      18470  allocator->GetRecorder()->RecordCreatePool(allocator->GetCurrentFrameIndex(), *pCreateInfo, *pPool);
      +
      18471  }
      +
      18472 #endif
      +
      18473 
      +
      18474  return res;
      +
      18475 }
      +
      18476 
      +
      18477 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyPool(
      +
      18478  VmaAllocator allocator,
      +
      18479  VmaPool pool)
      +
      18480 {
      +
      18481  VMA_ASSERT(allocator);
      +
      18482 
      +
      18483  if(pool == VK_NULL_HANDLE)
      +
      18484  {
      +
      18485  return;
      +
      18486  }
      +
      18487 
      +
      18488  VMA_DEBUG_LOG("vmaDestroyPool");
      +
      18489 
      +
      18490  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18491 
      +
      18492 #if VMA_RECORDING_ENABLED
      +
      18493  if(allocator->GetRecorder() != VMA_NULL)
      +
      18494  {
      +
      18495  allocator->GetRecorder()->RecordDestroyPool(allocator->GetCurrentFrameIndex(), pool);
      +
      18496  }
      +
      18497 #endif
      +
      18498 
      +
      18499  allocator->DestroyPool(pool);
      +
      18500 }
      +
      18501 
      +
      18502 VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolStats(
      +
      18503  VmaAllocator allocator,
      +
      18504  VmaPool pool,
      +
      18505  VmaPoolStats* pPoolStats)
      +
      18506 {
      +
      18507  VMA_ASSERT(allocator && pool && pPoolStats);
      18508 
      -
      18509  return result;
      -
      18510 }
      -
      18511 
      -
      18512 VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemory(
      -
      18513  VmaAllocator allocator,
      -
      18514  VmaAllocation allocation)
      -
      18515 {
      -
      18516  VMA_ASSERT(allocator);
      -
      18517 
      -
      18518  if(allocation == VK_NULL_HANDLE)
      -
      18519  {
      -
      18520  return;
      -
      18521  }
      +
      18509  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18510 
      +
      18511  allocator->GetPoolStats(pool, pPoolStats);
      +
      18512 }
      +
      18513 
      +
      18514 VMA_CALL_PRE void VMA_CALL_POST vmaMakePoolAllocationsLost(
      +
      18515  VmaAllocator allocator,
      +
      18516  VmaPool pool,
      +
      18517  size_t* pLostAllocationCount)
      +
      18518 {
      +
      18519  VMA_ASSERT(allocator && pool);
      +
      18520 
      +
      18521  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      18522 
      -
      18523  VMA_DEBUG_LOG("vmaFreeMemory");
      -
      18524 
      -
      18525  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18526 
      -
      18527 #if VMA_RECORDING_ENABLED
      -
      18528  if(allocator->GetRecorder() != VMA_NULL)
      -
      18529  {
      -
      18530  allocator->GetRecorder()->RecordFreeMemory(
      -
      18531  allocator->GetCurrentFrameIndex(),
      -
      18532  allocation);
      -
      18533  }
      -
      18534 #endif
      -
      18535 
      -
      18536  allocator->FreeMemory(
      -
      18537  1, // allocationCount
      -
      18538  &allocation);
      -
      18539 }
      +
      18523 #if VMA_RECORDING_ENABLED
      +
      18524  if(allocator->GetRecorder() != VMA_NULL)
      +
      18525  {
      +
      18526  allocator->GetRecorder()->RecordMakePoolAllocationsLost(allocator->GetCurrentFrameIndex(), pool);
      +
      18527  }
      +
      18528 #endif
      +
      18529 
      +
      18530  allocator->MakePoolAllocationsLost(pool, pLostAllocationCount);
      +
      18531 }
      +
      18532 
      +
      18533 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckPoolCorruption(VmaAllocator allocator, VmaPool pool)
      +
      18534 {
      +
      18535  VMA_ASSERT(allocator && pool);
      +
      18536 
      +
      18537  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18538 
      +
      18539  VMA_DEBUG_LOG("vmaCheckPoolCorruption");
      18540 
      -
      18541 VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemoryPages(
      -
      18542  VmaAllocator allocator,
      -
      18543  size_t allocationCount,
      -
      18544  const VmaAllocation* pAllocations)
      -
      18545 {
      -
      18546  if(allocationCount == 0)
      -
      18547  {
      -
      18548  return;
      -
      18549  }
      +
      18541  return allocator->CheckPoolCorruption(pool);
      +
      18542 }
      +
      18543 
      +
      18544 VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolName(
      +
      18545  VmaAllocator allocator,
      +
      18546  VmaPool pool,
      +
      18547  const char** ppName)
      +
      18548 {
      +
      18549  VMA_ASSERT(allocator && pool && ppName);
      18550 
      -
      18551  VMA_ASSERT(allocator);
      +
      18551  VMA_DEBUG_LOG("vmaGetPoolName");
      18552 
      -
      18553  VMA_DEBUG_LOG("vmaFreeMemoryPages");
      +
      18553  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      18554 
      -
      18555  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18556 
      -
      18557 #if VMA_RECORDING_ENABLED
      -
      18558  if(allocator->GetRecorder() != VMA_NULL)
      -
      18559  {
      -
      18560  allocator->GetRecorder()->RecordFreeMemoryPages(
      -
      18561  allocator->GetCurrentFrameIndex(),
      -
      18562  (uint64_t)allocationCount,
      -
      18563  pAllocations);
      -
      18564  }
      -
      18565 #endif
      +
      18555  *ppName = pool->GetName();
      +
      18556 }
      +
      18557 
      +
      18558 VMA_CALL_PRE void VMA_CALL_POST vmaSetPoolName(
      +
      18559  VmaAllocator allocator,
      +
      18560  VmaPool pool,
      +
      18561  const char* pName)
      +
      18562 {
      +
      18563  VMA_ASSERT(allocator && pool);
      +
      18564 
      +
      18565  VMA_DEBUG_LOG("vmaSetPoolName");
      18566 
      -
      18567  allocator->FreeMemory(allocationCount, pAllocations);
      -
      18568 }
      -
      18569 
      -
      18570 VMA_CALL_PRE VkResult VMA_CALL_POST vmaResizeAllocation(
      -
      18571  VmaAllocator allocator,
      -
      18572  VmaAllocation allocation,
      -
      18573  VkDeviceSize newSize)
      -
      18574 {
      -
      18575  VMA_ASSERT(allocator && allocation);
      -
      18576 
      -
      18577  VMA_DEBUG_LOG("vmaResizeAllocation");
      +
      18567  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18568 
      +
      18569  pool->SetName(pName);
      +
      18570 
      +
      18571 #if VMA_RECORDING_ENABLED
      +
      18572  if(allocator->GetRecorder() != VMA_NULL)
      +
      18573  {
      +
      18574  allocator->GetRecorder()->RecordSetPoolName(allocator->GetCurrentFrameIndex(), pool, pName);
      +
      18575  }
      +
      18576 #endif
      +
      18577 }
      18578 
      -
      18579  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18580 
      -
      18581  return allocator->ResizeAllocation(allocation, newSize);
      -
      18582 }
      -
      18583 
      -
      18584 VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo(
      -
      18585  VmaAllocator allocator,
      -
      18586  VmaAllocation allocation,
      -
      18587  VmaAllocationInfo* pAllocationInfo)
      -
      18588 {
      -
      18589  VMA_ASSERT(allocator && allocation && pAllocationInfo);
      -
      18590 
      -
      18591  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18592 
      -
      18593 #if VMA_RECORDING_ENABLED
      -
      18594  if(allocator->GetRecorder() != VMA_NULL)
      -
      18595  {
      -
      18596  allocator->GetRecorder()->RecordGetAllocationInfo(
      -
      18597  allocator->GetCurrentFrameIndex(),
      -
      18598  allocation);
      -
      18599  }
      -
      18600 #endif
      -
      18601 
      -
      18602  allocator->GetAllocationInfo(allocation, pAllocationInfo);
      -
      18603 }
      -
      18604 
      -
      18605 VMA_CALL_PRE VkBool32 VMA_CALL_POST vmaTouchAllocation(
      -
      18606  VmaAllocator allocator,
      -
      18607  VmaAllocation allocation)
      -
      18608 {
      -
      18609  VMA_ASSERT(allocator && allocation);
      -
      18610 
      -
      18611  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18612 
      -
      18613 #if VMA_RECORDING_ENABLED
      -
      18614  if(allocator->GetRecorder() != VMA_NULL)
      -
      18615  {
      -
      18616  allocator->GetRecorder()->RecordTouchAllocation(
      -
      18617  allocator->GetCurrentFrameIndex(),
      -
      18618  allocation);
      -
      18619  }
      -
      18620 #endif
      -
      18621 
      -
      18622  return allocator->TouchAllocation(allocation);
      -
      18623 }
      -
      18624 
      -
      18625 VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationUserData(
      -
      18626  VmaAllocator allocator,
      -
      18627  VmaAllocation allocation,
      -
      18628  void* pUserData)
      -
      18629 {
      -
      18630  VMA_ASSERT(allocator && allocation);
      -
      18631 
      -
      18632  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18633 
      -
      18634  allocation->SetUserData(allocator, pUserData);
      +
      18579 VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemory(
      +
      18580  VmaAllocator allocator,
      +
      18581  const VkMemoryRequirements* pVkMemoryRequirements,
      +
      18582  const VmaAllocationCreateInfo* pCreateInfo,
      +
      18583  VmaAllocation* pAllocation,
      +
      18584  VmaAllocationInfo* pAllocationInfo)
      +
      18585 {
      +
      18586  VMA_ASSERT(allocator && pVkMemoryRequirements && pCreateInfo && pAllocation);
      +
      18587 
      +
      18588  VMA_DEBUG_LOG("vmaAllocateMemory");
      +
      18589 
      +
      18590  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18591 
      +
      18592  VkResult result = allocator->AllocateMemory(
      +
      18593  *pVkMemoryRequirements,
      +
      18594  false, // requiresDedicatedAllocation
      +
      18595  false, // prefersDedicatedAllocation
      +
      18596  VK_NULL_HANDLE, // dedicatedBuffer
      +
      18597  UINT32_MAX, // dedicatedBufferUsage
      +
      18598  VK_NULL_HANDLE, // dedicatedImage
      +
      18599  *pCreateInfo,
      +
      18600  VMA_SUBALLOCATION_TYPE_UNKNOWN,
      +
      18601  1, // allocationCount
      +
      18602  pAllocation);
      +
      18603 
      +
      18604 #if VMA_RECORDING_ENABLED
      +
      18605  if(allocator->GetRecorder() != VMA_NULL)
      +
      18606  {
      +
      18607  allocator->GetRecorder()->RecordAllocateMemory(
      +
      18608  allocator->GetCurrentFrameIndex(),
      +
      18609  *pVkMemoryRequirements,
      +
      18610  *pCreateInfo,
      +
      18611  *pAllocation);
      +
      18612  }
      +
      18613 #endif
      +
      18614 
      +
      18615  if(pAllocationInfo != VMA_NULL && result == VK_SUCCESS)
      +
      18616  {
      +
      18617  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
      +
      18618  }
      +
      18619 
      +
      18620  return result;
      +
      18621 }
      +
      18622 
      +
      18623 VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryPages(
      +
      18624  VmaAllocator allocator,
      +
      18625  const VkMemoryRequirements* pVkMemoryRequirements,
      +
      18626  const VmaAllocationCreateInfo* pCreateInfo,
      +
      18627  size_t allocationCount,
      +
      18628  VmaAllocation* pAllocations,
      +
      18629  VmaAllocationInfo* pAllocationInfo)
      +
      18630 {
      +
      18631  if(allocationCount == 0)
      +
      18632  {
      +
      18633  return VK_SUCCESS;
      +
      18634  }
      18635 
      -
      18636 #if VMA_RECORDING_ENABLED
      -
      18637  if(allocator->GetRecorder() != VMA_NULL)
      -
      18638  {
      -
      18639  allocator->GetRecorder()->RecordSetAllocationUserData(
      -
      18640  allocator->GetCurrentFrameIndex(),
      -
      18641  allocation,
      -
      18642  pUserData);
      -
      18643  }
      -
      18644 #endif
      -
      18645 }
      -
      18646 
      -
      18647 VMA_CALL_PRE void VMA_CALL_POST vmaCreateLostAllocation(
      -
      18648  VmaAllocator allocator,
      -
      18649  VmaAllocation* pAllocation)
      -
      18650 {
      -
      18651  VMA_ASSERT(allocator && pAllocation);
      -
      18652 
      -
      18653  VMA_DEBUG_GLOBAL_MUTEX_LOCK;
      -
      18654 
      -
      18655  allocator->CreateLostAllocation(pAllocation);
      -
      18656 
      -
      18657 #if VMA_RECORDING_ENABLED
      -
      18658  if(allocator->GetRecorder() != VMA_NULL)
      -
      18659  {
      -
      18660  allocator->GetRecorder()->RecordCreateLostAllocation(
      -
      18661  allocator->GetCurrentFrameIndex(),
      -
      18662  *pAllocation);
      +
      18636  VMA_ASSERT(allocator && pVkMemoryRequirements && pCreateInfo && pAllocations);
      +
      18637 
      +
      18638  VMA_DEBUG_LOG("vmaAllocateMemoryPages");
      +
      18639 
      +
      18640  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18641 
      +
      18642  VkResult result = allocator->AllocateMemory(
      +
      18643  *pVkMemoryRequirements,
      +
      18644  false, // requiresDedicatedAllocation
      +
      18645  false, // prefersDedicatedAllocation
      +
      18646  VK_NULL_HANDLE, // dedicatedBuffer
      +
      18647  UINT32_MAX, // dedicatedBufferUsage
      +
      18648  VK_NULL_HANDLE, // dedicatedImage
      +
      18649  *pCreateInfo,
      +
      18650  VMA_SUBALLOCATION_TYPE_UNKNOWN,
      +
      18651  allocationCount,
      +
      18652  pAllocations);
      +
      18653 
      +
      18654 #if VMA_RECORDING_ENABLED
      +
      18655  if(allocator->GetRecorder() != VMA_NULL)
      +
      18656  {
      +
      18657  allocator->GetRecorder()->RecordAllocateMemoryPages(
      +
      18658  allocator->GetCurrentFrameIndex(),
      +
      18659  *pVkMemoryRequirements,
      +
      18660  *pCreateInfo,
      +
      18661  (uint64_t)allocationCount,
      +
      18662  pAllocations);
      18663  }
      18664 #endif
      -
      18665 }
      -
      18666 
      -
      18667 VMA_CALL_PRE VkResult VMA_CALL_POST vmaMapMemory(
      -
      18668  VmaAllocator allocator,
      -
      18669  VmaAllocation allocation,
      -
      18670  void** ppData)
      -
      18671 {
      -
      18672  VMA_ASSERT(allocator && allocation && ppData);
      +
      18665 
      +
      18666  if(pAllocationInfo != VMA_NULL && result == VK_SUCCESS)
      +
      18667  {
      +
      18668  for(size_t i = 0; i < allocationCount; ++i)
      +
      18669  {
      +
      18670  allocator->GetAllocationInfo(pAllocations[i], pAllocationInfo + i);
      +
      18671  }
      +
      18672  }
      18673 
      -
      18674  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18675 
      -
      18676  VkResult res = allocator->Map(allocation, ppData);
      -
      18677 
      -
      18678 #if VMA_RECORDING_ENABLED
      -
      18679  if(allocator->GetRecorder() != VMA_NULL)
      -
      18680  {
      -
      18681  allocator->GetRecorder()->RecordMapMemory(
      -
      18682  allocator->GetCurrentFrameIndex(),
      -
      18683  allocation);
      -
      18684  }
      -
      18685 #endif
      -
      18686 
      -
      18687  return res;
      -
      18688 }
      +
      18674  return result;
      +
      18675 }
      +
      18676 
      +
      18677 VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForBuffer(
      +
      18678  VmaAllocator allocator,
      +
      18679  VkBuffer buffer,
      +
      18680  const VmaAllocationCreateInfo* pCreateInfo,
      +
      18681  VmaAllocation* pAllocation,
      +
      18682  VmaAllocationInfo* pAllocationInfo)
      +
      18683 {
      +
      18684  VMA_ASSERT(allocator && buffer != VK_NULL_HANDLE && pCreateInfo && pAllocation);
      +
      18685 
      +
      18686  VMA_DEBUG_LOG("vmaAllocateMemoryForBuffer");
      +
      18687 
      +
      18688  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      18689 
      -
      18690 VMA_CALL_PRE void VMA_CALL_POST vmaUnmapMemory(
      -
      18691  VmaAllocator allocator,
      -
      18692  VmaAllocation allocation)
      -
      18693 {
      -
      18694  VMA_ASSERT(allocator && allocation);
      -
      18695 
      -
      18696  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18697 
      -
      18698 #if VMA_RECORDING_ENABLED
      -
      18699  if(allocator->GetRecorder() != VMA_NULL)
      -
      18700  {
      -
      18701  allocator->GetRecorder()->RecordUnmapMemory(
      -
      18702  allocator->GetCurrentFrameIndex(),
      -
      18703  allocation);
      -
      18704  }
      -
      18705 #endif
      -
      18706 
      -
      18707  allocator->Unmap(allocation);
      -
      18708 }
      -
      18709 
      -
      18710 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocation(VmaAllocator allocator, VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size)
      -
      18711 {
      -
      18712  VMA_ASSERT(allocator && allocation);
      -
      18713 
      -
      18714  VMA_DEBUG_LOG("vmaFlushAllocation");
      -
      18715 
      -
      18716  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18717 
      -
      18718  const VkResult res = allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_FLUSH);
      -
      18719 
      -
      18720 #if VMA_RECORDING_ENABLED
      -
      18721  if(allocator->GetRecorder() != VMA_NULL)
      -
      18722  {
      -
      18723  allocator->GetRecorder()->RecordFlushAllocation(
      -
      18724  allocator->GetCurrentFrameIndex(),
      -
      18725  allocation, offset, size);
      -
      18726  }
      -
      18727 #endif
      -
      18728 
      -
      18729  return res;
      -
      18730 }
      -
      18731 
      -
      18732 VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation(VmaAllocator allocator, VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size)
      -
      18733 {
      -
      18734  VMA_ASSERT(allocator && allocation);
      -
      18735 
      -
      18736  VMA_DEBUG_LOG("vmaInvalidateAllocation");
      -
      18737 
      -
      18738  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18739 
      -
      18740  const VkResult res = allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_INVALIDATE);
      -
      18741 
      -
      18742 #if VMA_RECORDING_ENABLED
      -
      18743  if(allocator->GetRecorder() != VMA_NULL)
      -
      18744  {
      -
      18745  allocator->GetRecorder()->RecordInvalidateAllocation(
      -
      18746  allocator->GetCurrentFrameIndex(),
      -
      18747  allocation, offset, size);
      -
      18748  }
      -
      18749 #endif
      -
      18750 
      -
      18751  return res;
      -
      18752 }
      -
      18753 
      -
      18754 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations(
      -
      18755  VmaAllocator allocator,
      -
      18756  uint32_t allocationCount,
      -
      18757  const VmaAllocation* allocations,
      -
      18758  const VkDeviceSize* offsets,
      -
      18759  const VkDeviceSize* sizes)
      -
      18760 {
      -
      18761  VMA_ASSERT(allocator);
      -
      18762 
      -
      18763  if(allocationCount == 0)
      -
      18764  {
      -
      18765  return VK_SUCCESS;
      -
      18766  }
      -
      18767 
      -
      18768  VMA_ASSERT(allocations);
      -
      18769 
      -
      18770  VMA_DEBUG_LOG("vmaFlushAllocations");
      -
      18771 
      -
      18772  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18690  VkMemoryRequirements vkMemReq = {};
      +
      18691  bool requiresDedicatedAllocation = false;
      +
      18692  bool prefersDedicatedAllocation = false;
      +
      18693  allocator->GetBufferMemoryRequirements(buffer, vkMemReq,
      +
      18694  requiresDedicatedAllocation,
      +
      18695  prefersDedicatedAllocation);
      +
      18696 
      +
      18697  VkResult result = allocator->AllocateMemory(
      +
      18698  vkMemReq,
      +
      18699  requiresDedicatedAllocation,
      +
      18700  prefersDedicatedAllocation,
      +
      18701  buffer, // dedicatedBuffer
      +
      18702  UINT32_MAX, // dedicatedBufferUsage
      +
      18703  VK_NULL_HANDLE, // dedicatedImage
      +
      18704  *pCreateInfo,
      +
      18705  VMA_SUBALLOCATION_TYPE_BUFFER,
      +
      18706  1, // allocationCount
      +
      18707  pAllocation);
      +
      18708 
      +
      18709 #if VMA_RECORDING_ENABLED
      +
      18710  if(allocator->GetRecorder() != VMA_NULL)
      +
      18711  {
      +
      18712  allocator->GetRecorder()->RecordAllocateMemoryForBuffer(
      +
      18713  allocator->GetCurrentFrameIndex(),
      +
      18714  vkMemReq,
      +
      18715  requiresDedicatedAllocation,
      +
      18716  prefersDedicatedAllocation,
      +
      18717  *pCreateInfo,
      +
      18718  *pAllocation);
      +
      18719  }
      +
      18720 #endif
      +
      18721 
      +
      18722  if(pAllocationInfo && result == VK_SUCCESS)
      +
      18723  {
      +
      18724  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
      +
      18725  }
      +
      18726 
      +
      18727  return result;
      +
      18728 }
      +
      18729 
      +
      18730 VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForImage(
      +
      18731  VmaAllocator allocator,
      +
      18732  VkImage image,
      +
      18733  const VmaAllocationCreateInfo* pCreateInfo,
      +
      18734  VmaAllocation* pAllocation,
      +
      18735  VmaAllocationInfo* pAllocationInfo)
      +
      18736 {
      +
      18737  VMA_ASSERT(allocator && image != VK_NULL_HANDLE && pCreateInfo && pAllocation);
      +
      18738 
      +
      18739  VMA_DEBUG_LOG("vmaAllocateMemoryForImage");
      +
      18740 
      +
      18741  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18742 
      +
      18743  VkMemoryRequirements vkMemReq = {};
      +
      18744  bool requiresDedicatedAllocation = false;
      +
      18745  bool prefersDedicatedAllocation = false;
      +
      18746  allocator->GetImageMemoryRequirements(image, vkMemReq,
      +
      18747  requiresDedicatedAllocation, prefersDedicatedAllocation);
      +
      18748 
      +
      18749  VkResult result = allocator->AllocateMemory(
      +
      18750  vkMemReq,
      +
      18751  requiresDedicatedAllocation,
      +
      18752  prefersDedicatedAllocation,
      +
      18753  VK_NULL_HANDLE, // dedicatedBuffer
      +
      18754  UINT32_MAX, // dedicatedBufferUsage
      +
      18755  image, // dedicatedImage
      +
      18756  *pCreateInfo,
      +
      18757  VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN,
      +
      18758  1, // allocationCount
      +
      18759  pAllocation);
      +
      18760 
      +
      18761 #if VMA_RECORDING_ENABLED
      +
      18762  if(allocator->GetRecorder() != VMA_NULL)
      +
      18763  {
      +
      18764  allocator->GetRecorder()->RecordAllocateMemoryForImage(
      +
      18765  allocator->GetCurrentFrameIndex(),
      +
      18766  vkMemReq,
      +
      18767  requiresDedicatedAllocation,
      +
      18768  prefersDedicatedAllocation,
      +
      18769  *pCreateInfo,
      +
      18770  *pAllocation);
      +
      18771  }
      +
      18772 #endif
      18773 
      -
      18774  const VkResult res = allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_FLUSH);
      -
      18775 
      -
      18776 #if VMA_RECORDING_ENABLED
      -
      18777  if(allocator->GetRecorder() != VMA_NULL)
      -
      18778  {
      -
      18779  //TODO
      -
      18780  }
      -
      18781 #endif
      -
      18782 
      -
      18783  return res;
      -
      18784 }
      -
      18785 
      -
      18786 VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations(
      -
      18787  VmaAllocator allocator,
      -
      18788  uint32_t allocationCount,
      -
      18789  const VmaAllocation* allocations,
      -
      18790  const VkDeviceSize* offsets,
      -
      18791  const VkDeviceSize* sizes)
      -
      18792 {
      -
      18793  VMA_ASSERT(allocator);
      +
      18774  if(pAllocationInfo && result == VK_SUCCESS)
      +
      18775  {
      +
      18776  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
      +
      18777  }
      +
      18778 
      +
      18779  return result;
      +
      18780 }
      +
      18781 
      +
      18782 VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemory(
      +
      18783  VmaAllocator allocator,
      +
      18784  VmaAllocation allocation)
      +
      18785 {
      +
      18786  VMA_ASSERT(allocator);
      +
      18787 
      +
      18788  if(allocation == VK_NULL_HANDLE)
      +
      18789  {
      +
      18790  return;
      +
      18791  }
      +
      18792 
      +
      18793  VMA_DEBUG_LOG("vmaFreeMemory");
      18794 
      -
      18795  if(allocationCount == 0)
      -
      18796  {
      -
      18797  return VK_SUCCESS;
      -
      18798  }
      -
      18799 
      -
      18800  VMA_ASSERT(allocations);
      -
      18801 
      -
      18802  VMA_DEBUG_LOG("vmaInvalidateAllocations");
      -
      18803 
      -
      18804  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18795  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18796 
      +
      18797 #if VMA_RECORDING_ENABLED
      +
      18798  if(allocator->GetRecorder() != VMA_NULL)
      +
      18799  {
      +
      18800  allocator->GetRecorder()->RecordFreeMemory(
      +
      18801  allocator->GetCurrentFrameIndex(),
      +
      18802  allocation);
      +
      18803  }
      +
      18804 #endif
      18805 
      -
      18806  const VkResult res = allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_INVALIDATE);
      -
      18807 
      -
      18808 #if VMA_RECORDING_ENABLED
      -
      18809  if(allocator->GetRecorder() != VMA_NULL)
      -
      18810  {
      -
      18811  //TODO
      -
      18812  }
      -
      18813 #endif
      -
      18814 
      -
      18815  return res;
      -
      18816 }
      -
      18817 
      -
      18818 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption(VmaAllocator allocator, uint32_t memoryTypeBits)
      -
      18819 {
      -
      18820  VMA_ASSERT(allocator);
      -
      18821 
      -
      18822  VMA_DEBUG_LOG("vmaCheckCorruption");
      -
      18823 
      -
      18824  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18825 
      -
      18826  return allocator->CheckCorruption(memoryTypeBits);
      -
      18827 }
      -
      18828 
      -
      18829 VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragment(
      -
      18830  VmaAllocator allocator,
      -
      18831  const VmaAllocation* pAllocations,
      -
      18832  size_t allocationCount,
      -
      18833  VkBool32* pAllocationsChanged,
      -
      18834  const VmaDefragmentationInfo *pDefragmentationInfo,
      -
      18835  VmaDefragmentationStats* pDefragmentationStats)
      -
      18836 {
      -
      18837  // Deprecated interface, reimplemented using new one.
      -
      18838 
      -
      18839  VmaDefragmentationInfo2 info2 = {};
      -
      18840  info2.allocationCount = (uint32_t)allocationCount;
      -
      18841  info2.pAllocations = pAllocations;
      -
      18842  info2.pAllocationsChanged = pAllocationsChanged;
      -
      18843  if(pDefragmentationInfo != VMA_NULL)
      -
      18844  {
      -
      18845  info2.maxCpuAllocationsToMove = pDefragmentationInfo->maxAllocationsToMove;
      -
      18846  info2.maxCpuBytesToMove = pDefragmentationInfo->maxBytesToMove;
      -
      18847  }
      -
      18848  else
      -
      18849  {
      -
      18850  info2.maxCpuAllocationsToMove = UINT32_MAX;
      -
      18851  info2.maxCpuBytesToMove = VK_WHOLE_SIZE;
      -
      18852  }
      -
      18853  // info2.flags, maxGpuAllocationsToMove, maxGpuBytesToMove, commandBuffer deliberately left zero.
      -
      18854 
      - -
      18856  VkResult res = vmaDefragmentationBegin(allocator, &info2, pDefragmentationStats, &ctx);
      -
      18857  if(res == VK_NOT_READY)
      -
      18858  {
      -
      18859  res = vmaDefragmentationEnd( allocator, ctx);
      -
      18860  }
      -
      18861  return res;
      -
      18862 }
      -
      18863 
      -
      18864 VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragmentationBegin(
      -
      18865  VmaAllocator allocator,
      -
      18866  const VmaDefragmentationInfo2* pInfo,
      -
      18867  VmaDefragmentationStats* pStats,
      -
      18868  VmaDefragmentationContext *pContext)
      -
      18869 {
      -
      18870  VMA_ASSERT(allocator && pInfo && pContext);
      -
      18871 
      -
      18872  // Degenerate case: Nothing to defragment.
      -
      18873  if(pInfo->allocationCount == 0 && pInfo->poolCount == 0)
      -
      18874  {
      -
      18875  return VK_SUCCESS;
      -
      18876  }
      +
      18806  allocator->FreeMemory(
      +
      18807  1, // allocationCount
      +
      18808  &allocation);
      +
      18809 }
      +
      18810 
      +
      18811 VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemoryPages(
      +
      18812  VmaAllocator allocator,
      +
      18813  size_t allocationCount,
      +
      18814  const VmaAllocation* pAllocations)
      +
      18815 {
      +
      18816  if(allocationCount == 0)
      +
      18817  {
      +
      18818  return;
      +
      18819  }
      +
      18820 
      +
      18821  VMA_ASSERT(allocator);
      +
      18822 
      +
      18823  VMA_DEBUG_LOG("vmaFreeMemoryPages");
      +
      18824 
      +
      18825  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18826 
      +
      18827 #if VMA_RECORDING_ENABLED
      +
      18828  if(allocator->GetRecorder() != VMA_NULL)
      +
      18829  {
      +
      18830  allocator->GetRecorder()->RecordFreeMemoryPages(
      +
      18831  allocator->GetCurrentFrameIndex(),
      +
      18832  (uint64_t)allocationCount,
      +
      18833  pAllocations);
      +
      18834  }
      +
      18835 #endif
      +
      18836 
      +
      18837  allocator->FreeMemory(allocationCount, pAllocations);
      +
      18838 }
      +
      18839 
      +
      18840 VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo(
      +
      18841  VmaAllocator allocator,
      +
      18842  VmaAllocation allocation,
      +
      18843  VmaAllocationInfo* pAllocationInfo)
      +
      18844 {
      +
      18845  VMA_ASSERT(allocator && allocation && pAllocationInfo);
      +
      18846 
      +
      18847  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18848 
      +
      18849 #if VMA_RECORDING_ENABLED
      +
      18850  if(allocator->GetRecorder() != VMA_NULL)
      +
      18851  {
      +
      18852  allocator->GetRecorder()->RecordGetAllocationInfo(
      +
      18853  allocator->GetCurrentFrameIndex(),
      +
      18854  allocation);
      +
      18855  }
      +
      18856 #endif
      +
      18857 
      +
      18858  allocator->GetAllocationInfo(allocation, pAllocationInfo);
      +
      18859 }
      +
      18860 
      +
      18861 VMA_CALL_PRE VkBool32 VMA_CALL_POST vmaTouchAllocation(
      +
      18862  VmaAllocator allocator,
      +
      18863  VmaAllocation allocation)
      +
      18864 {
      +
      18865  VMA_ASSERT(allocator && allocation);
      +
      18866 
      +
      18867  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18868 
      +
      18869 #if VMA_RECORDING_ENABLED
      +
      18870  if(allocator->GetRecorder() != VMA_NULL)
      +
      18871  {
      +
      18872  allocator->GetRecorder()->RecordTouchAllocation(
      +
      18873  allocator->GetCurrentFrameIndex(),
      +
      18874  allocation);
      +
      18875  }
      +
      18876 #endif
      18877 
      -
      18878  VMA_ASSERT(pInfo->allocationCount == 0 || pInfo->pAllocations != VMA_NULL);
      -
      18879  VMA_ASSERT(pInfo->poolCount == 0 || pInfo->pPools != VMA_NULL);
      -
      18880  VMA_HEAVY_ASSERT(VmaValidatePointerArray(pInfo->allocationCount, pInfo->pAllocations));
      -
      18881  VMA_HEAVY_ASSERT(VmaValidatePointerArray(pInfo->poolCount, pInfo->pPools));
      -
      18882 
      -
      18883  VMA_DEBUG_LOG("vmaDefragmentationBegin");
      -
      18884 
      -
      18885  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18886 
      -
      18887  VkResult res = allocator->DefragmentationBegin(*pInfo, pStats, pContext);
      -
      18888 
      -
      18889 #if VMA_RECORDING_ENABLED
      -
      18890  if(allocator->GetRecorder() != VMA_NULL)
      -
      18891  {
      -
      18892  allocator->GetRecorder()->RecordDefragmentationBegin(
      -
      18893  allocator->GetCurrentFrameIndex(), *pInfo, *pContext);
      -
      18894  }
      -
      18895 #endif
      -
      18896 
      -
      18897  return res;
      -
      18898 }
      -
      18899 
      -
      18900 VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragmentationEnd(
      -
      18901  VmaAllocator allocator,
      -
      18902  VmaDefragmentationContext context)
      -
      18903 {
      -
      18904  VMA_ASSERT(allocator);
      -
      18905 
      -
      18906  VMA_DEBUG_LOG("vmaDefragmentationEnd");
      -
      18907 
      -
      18908  if(context != VK_NULL_HANDLE)
      -
      18909  {
      -
      18910  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18911 
      -
      18912 #if VMA_RECORDING_ENABLED
      -
      18913  if(allocator->GetRecorder() != VMA_NULL)
      -
      18914  {
      -
      18915  allocator->GetRecorder()->RecordDefragmentationEnd(
      -
      18916  allocator->GetCurrentFrameIndex(), context);
      -
      18917  }
      -
      18918 #endif
      -
      18919 
      -
      18920  return allocator->DefragmentationEnd(context);
      -
      18921  }
      -
      18922  else
      -
      18923  {
      -
      18924  return VK_SUCCESS;
      -
      18925  }
      -
      18926 }
      -
      18927 
      -
      18928 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentationPass(
      -
      18929  VmaAllocator allocator,
      -
      18930  VmaDefragmentationContext context,
      - -
      18932  )
      -
      18933 {
      -
      18934  VMA_ASSERT(allocator);
      -
      18935  VMA_ASSERT(pInfo);
      -
      18936 
      -
      18937  VMA_DEBUG_LOG("vmaBeginDefragmentationPass");
      -
      18938 
      -
      18939  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18940 
      -
      18941  if(context == VK_NULL_HANDLE)
      -
      18942  {
      -
      18943  pInfo->moveCount = 0;
      -
      18944  return VK_SUCCESS;
      -
      18945  }
      -
      18946 
      -
      18947  return allocator->DefragmentationPassBegin(pInfo, context);
      -
      18948 }
      -
      18949 VMA_CALL_PRE VkResult VMA_CALL_POST vmaEndDefragmentationPass(
      -
      18950  VmaAllocator allocator,
      -
      18951  VmaDefragmentationContext context)
      -
      18952 {
      -
      18953  VMA_ASSERT(allocator);
      -
      18954 
      -
      18955  VMA_DEBUG_LOG("vmaEndDefragmentationPass");
      -
      18956  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18957 
      -
      18958  if(context == VK_NULL_HANDLE)
      -
      18959  return VK_SUCCESS;
      -
      18960 
      -
      18961  return allocator->DefragmentationPassEnd(context);
      -
      18962 }
      -
      18963 
      -
      18964 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory(
      -
      18965  VmaAllocator allocator,
      -
      18966  VmaAllocation allocation,
      -
      18967  VkBuffer buffer)
      -
      18968 {
      -
      18969  VMA_ASSERT(allocator && allocation && buffer);
      -
      18970 
      -
      18971  VMA_DEBUG_LOG("vmaBindBufferMemory");
      -
      18972 
      -
      18973  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18974 
      -
      18975  return allocator->BindBufferMemory(allocation, 0, buffer, VMA_NULL);
      -
      18976 }
      -
      18977 
      -
      18978 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory2(
      -
      18979  VmaAllocator allocator,
      -
      18980  VmaAllocation allocation,
      -
      18981  VkDeviceSize allocationLocalOffset,
      -
      18982  VkBuffer buffer,
      -
      18983  const void* pNext)
      -
      18984 {
      -
      18985  VMA_ASSERT(allocator && allocation && buffer);
      -
      18986 
      -
      18987  VMA_DEBUG_LOG("vmaBindBufferMemory2");
      -
      18988 
      -
      18989  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      18990 
      -
      18991  return allocator->BindBufferMemory(allocation, allocationLocalOffset, buffer, pNext);
      -
      18992 }
      +
      18878  return allocator->TouchAllocation(allocation);
      +
      18879 }
      +
      18880 
      +
      18881 VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationUserData(
      +
      18882  VmaAllocator allocator,
      +
      18883  VmaAllocation allocation,
      +
      18884  void* pUserData)
      +
      18885 {
      +
      18886  VMA_ASSERT(allocator && allocation);
      +
      18887 
      +
      18888  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18889 
      +
      18890  allocation->SetUserData(allocator, pUserData);
      +
      18891 
      +
      18892 #if VMA_RECORDING_ENABLED
      +
      18893  if(allocator->GetRecorder() != VMA_NULL)
      +
      18894  {
      +
      18895  allocator->GetRecorder()->RecordSetAllocationUserData(
      +
      18896  allocator->GetCurrentFrameIndex(),
      +
      18897  allocation,
      +
      18898  pUserData);
      +
      18899  }
      +
      18900 #endif
      +
      18901 }
      +
      18902 
      +
      18903 VMA_CALL_PRE void VMA_CALL_POST vmaCreateLostAllocation(
      +
      18904  VmaAllocator allocator,
      +
      18905  VmaAllocation* pAllocation)
      +
      18906 {
      +
      18907  VMA_ASSERT(allocator && pAllocation);
      +
      18908 
      +
      18909  VMA_DEBUG_GLOBAL_MUTEX_LOCK;
      +
      18910 
      +
      18911  allocator->CreateLostAllocation(pAllocation);
      +
      18912 
      +
      18913 #if VMA_RECORDING_ENABLED
      +
      18914  if(allocator->GetRecorder() != VMA_NULL)
      +
      18915  {
      +
      18916  allocator->GetRecorder()->RecordCreateLostAllocation(
      +
      18917  allocator->GetCurrentFrameIndex(),
      +
      18918  *pAllocation);
      +
      18919  }
      +
      18920 #endif
      +
      18921 }
      +
      18922 
      +
      18923 VMA_CALL_PRE VkResult VMA_CALL_POST vmaMapMemory(
      +
      18924  VmaAllocator allocator,
      +
      18925  VmaAllocation allocation,
      +
      18926  void** ppData)
      +
      18927 {
      +
      18928  VMA_ASSERT(allocator && allocation && ppData);
      +
      18929 
      +
      18930  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18931 
      +
      18932  VkResult res = allocator->Map(allocation, ppData);
      +
      18933 
      +
      18934 #if VMA_RECORDING_ENABLED
      +
      18935  if(allocator->GetRecorder() != VMA_NULL)
      +
      18936  {
      +
      18937  allocator->GetRecorder()->RecordMapMemory(
      +
      18938  allocator->GetCurrentFrameIndex(),
      +
      18939  allocation);
      +
      18940  }
      +
      18941 #endif
      +
      18942 
      +
      18943  return res;
      +
      18944 }
      +
      18945 
      +
      18946 VMA_CALL_PRE void VMA_CALL_POST vmaUnmapMemory(
      +
      18947  VmaAllocator allocator,
      +
      18948  VmaAllocation allocation)
      +
      18949 {
      +
      18950  VMA_ASSERT(allocator && allocation);
      +
      18951 
      +
      18952  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18953 
      +
      18954 #if VMA_RECORDING_ENABLED
      +
      18955  if(allocator->GetRecorder() != VMA_NULL)
      +
      18956  {
      +
      18957  allocator->GetRecorder()->RecordUnmapMemory(
      +
      18958  allocator->GetCurrentFrameIndex(),
      +
      18959  allocation);
      +
      18960  }
      +
      18961 #endif
      +
      18962 
      +
      18963  allocator->Unmap(allocation);
      +
      18964 }
      +
      18965 
      +
      18966 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocation(VmaAllocator allocator, VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size)
      +
      18967 {
      +
      18968  VMA_ASSERT(allocator && allocation);
      +
      18969 
      +
      18970  VMA_DEBUG_LOG("vmaFlushAllocation");
      +
      18971 
      +
      18972  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18973 
      +
      18974  const VkResult res = allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_FLUSH);
      +
      18975 
      +
      18976 #if VMA_RECORDING_ENABLED
      +
      18977  if(allocator->GetRecorder() != VMA_NULL)
      +
      18978  {
      +
      18979  allocator->GetRecorder()->RecordFlushAllocation(
      +
      18980  allocator->GetCurrentFrameIndex(),
      +
      18981  allocation, offset, size);
      +
      18982  }
      +
      18983 #endif
      +
      18984 
      +
      18985  return res;
      +
      18986 }
      +
      18987 
      +
      18988 VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation(VmaAllocator allocator, VmaAllocation allocation, VkDeviceSize offset, VkDeviceSize size)
      +
      18989 {
      +
      18990  VMA_ASSERT(allocator && allocation);
      +
      18991 
      +
      18992  VMA_DEBUG_LOG("vmaInvalidateAllocation");
      18993 
      -
      18994 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory(
      -
      18995  VmaAllocator allocator,
      -
      18996  VmaAllocation allocation,
      -
      18997  VkImage image)
      -
      18998 {
      -
      18999  VMA_ASSERT(allocator && allocation && image);
      -
      19000 
      -
      19001  VMA_DEBUG_LOG("vmaBindImageMemory");
      -
      19002 
      -
      19003  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      19004 
      -
      19005  return allocator->BindImageMemory(allocation, 0, image, VMA_NULL);
      -
      19006 }
      -
      19007 
      -
      19008 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory2(
      -
      19009  VmaAllocator allocator,
      -
      19010  VmaAllocation allocation,
      -
      19011  VkDeviceSize allocationLocalOffset,
      -
      19012  VkImage image,
      -
      19013  const void* pNext)
      -
      19014 {
      -
      19015  VMA_ASSERT(allocator && allocation && image);
      -
      19016 
      -
      19017  VMA_DEBUG_LOG("vmaBindImageMemory2");
      +
      18994  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      18995 
      +
      18996  const VkResult res = allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_INVALIDATE);
      +
      18997 
      +
      18998 #if VMA_RECORDING_ENABLED
      +
      18999  if(allocator->GetRecorder() != VMA_NULL)
      +
      19000  {
      +
      19001  allocator->GetRecorder()->RecordInvalidateAllocation(
      +
      19002  allocator->GetCurrentFrameIndex(),
      +
      19003  allocation, offset, size);
      +
      19004  }
      +
      19005 #endif
      +
      19006 
      +
      19007  return res;
      +
      19008 }
      +
      19009 
      +
      19010 VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations(
      +
      19011  VmaAllocator allocator,
      +
      19012  uint32_t allocationCount,
      +
      19013  const VmaAllocation* allocations,
      +
      19014  const VkDeviceSize* offsets,
      +
      19015  const VkDeviceSize* sizes)
      +
      19016 {
      +
      19017  VMA_ASSERT(allocator);
      19018 
      -
      19019  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      19020 
      -
      19021  return allocator->BindImageMemory(allocation, allocationLocalOffset, image, pNext);
      -
      19022 }
      +
      19019  if(allocationCount == 0)
      +
      19020  {
      +
      19021  return VK_SUCCESS;
      +
      19022  }
      19023 
      -
      19024 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer(
      -
      19025  VmaAllocator allocator,
      -
      19026  const VkBufferCreateInfo* pBufferCreateInfo,
      -
      19027  const VmaAllocationCreateInfo* pAllocationCreateInfo,
      -
      19028  VkBuffer* pBuffer,
      -
      19029  VmaAllocation* pAllocation,
      -
      19030  VmaAllocationInfo* pAllocationInfo)
      -
      19031 {
      -
      19032  VMA_ASSERT(allocator && pBufferCreateInfo && pAllocationCreateInfo && pBuffer && pAllocation);
      -
      19033 
      -
      19034  if(pBufferCreateInfo->size == 0)
      -
      19035  {
      -
      19036  return VK_ERROR_VALIDATION_FAILED_EXT;
      -
      19037  }
      -
      19038  if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY) != 0 &&
      -
      19039  !allocator->m_UseKhrBufferDeviceAddress)
      -
      19040  {
      -
      19041  VMA_ASSERT(0 && "Creating a buffer with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT is not valid if VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT was not used.");
      -
      19042  return VK_ERROR_VALIDATION_FAILED_EXT;
      -
      19043  }
      -
      19044 
      -
      19045  VMA_DEBUG_LOG("vmaCreateBuffer");
      -
      19046 
      -
      19047  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      19048 
      -
      19049  *pBuffer = VK_NULL_HANDLE;
      -
      19050  *pAllocation = VK_NULL_HANDLE;
      -
      19051 
      -
      19052  // 1. Create VkBuffer.
      -
      19053  VkResult res = (*allocator->GetVulkanFunctions().vkCreateBuffer)(
      -
      19054  allocator->m_hDevice,
      -
      19055  pBufferCreateInfo,
      -
      19056  allocator->GetAllocationCallbacks(),
      -
      19057  pBuffer);
      -
      19058  if(res >= 0)
      -
      19059  {
      -
      19060  // 2. vkGetBufferMemoryRequirements.
      -
      19061  VkMemoryRequirements vkMemReq = {};
      -
      19062  bool requiresDedicatedAllocation = false;
      -
      19063  bool prefersDedicatedAllocation = false;
      -
      19064  allocator->GetBufferMemoryRequirements(*pBuffer, vkMemReq,
      -
      19065  requiresDedicatedAllocation, prefersDedicatedAllocation);
      -
      19066 
      -
      19067  // 3. Allocate memory using allocator.
      -
      19068  res = allocator->AllocateMemory(
      -
      19069  vkMemReq,
      -
      19070  requiresDedicatedAllocation,
      -
      19071  prefersDedicatedAllocation,
      -
      19072  *pBuffer, // dedicatedBuffer
      -
      19073  pBufferCreateInfo->usage, // dedicatedBufferUsage
      -
      19074  VK_NULL_HANDLE, // dedicatedImage
      -
      19075  *pAllocationCreateInfo,
      -
      19076  VMA_SUBALLOCATION_TYPE_BUFFER,
      -
      19077  1, // allocationCount
      -
      19078  pAllocation);
      +
      19024  VMA_ASSERT(allocations);
      +
      19025 
      +
      19026  VMA_DEBUG_LOG("vmaFlushAllocations");
      +
      19027 
      +
      19028  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      19029 
      +
      19030  const VkResult res = allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_FLUSH);
      +
      19031 
      +
      19032 #if VMA_RECORDING_ENABLED
      +
      19033  if(allocator->GetRecorder() != VMA_NULL)
      +
      19034  {
      +
      19035  //TODO
      +
      19036  }
      +
      19037 #endif
      +
      19038 
      +
      19039  return res;
      +
      19040 }
      +
      19041 
      +
      19042 VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations(
      +
      19043  VmaAllocator allocator,
      +
      19044  uint32_t allocationCount,
      +
      19045  const VmaAllocation* allocations,
      +
      19046  const VkDeviceSize* offsets,
      +
      19047  const VkDeviceSize* sizes)
      +
      19048 {
      +
      19049  VMA_ASSERT(allocator);
      +
      19050 
      +
      19051  if(allocationCount == 0)
      +
      19052  {
      +
      19053  return VK_SUCCESS;
      +
      19054  }
      +
      19055 
      +
      19056  VMA_ASSERT(allocations);
      +
      19057 
      +
      19058  VMA_DEBUG_LOG("vmaInvalidateAllocations");
      +
      19059 
      +
      19060  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      19061 
      +
      19062  const VkResult res = allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_INVALIDATE);
      +
      19063 
      +
      19064 #if VMA_RECORDING_ENABLED
      +
      19065  if(allocator->GetRecorder() != VMA_NULL)
      +
      19066  {
      +
      19067  //TODO
      +
      19068  }
      +
      19069 #endif
      +
      19070 
      +
      19071  return res;
      +
      19072 }
      +
      19073 
      +
      19074 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption(VmaAllocator allocator, uint32_t memoryTypeBits)
      +
      19075 {
      +
      19076  VMA_ASSERT(allocator);
      +
      19077 
      +
      19078  VMA_DEBUG_LOG("vmaCheckCorruption");
      19079 
      -
      19080 #if VMA_RECORDING_ENABLED
      -
      19081  if(allocator->GetRecorder() != VMA_NULL)
      -
      19082  {
      -
      19083  allocator->GetRecorder()->RecordCreateBuffer(
      -
      19084  allocator->GetCurrentFrameIndex(),
      -
      19085  *pBufferCreateInfo,
      -
      19086  *pAllocationCreateInfo,
      -
      19087  *pAllocation);
      -
      19088  }
      -
      19089 #endif
      -
      19090 
      -
      19091  if(res >= 0)
      -
      19092  {
      -
      19093  // 3. Bind buffer with memory.
      -
      19094  if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0)
      -
      19095  {
      -
      19096  res = allocator->BindBufferMemory(*pAllocation, 0, *pBuffer, VMA_NULL);
      -
      19097  }
      -
      19098  if(res >= 0)
      -
      19099  {
      -
      19100  // All steps succeeded.
      -
      19101  #if VMA_STATS_STRING_ENABLED
      -
      19102  (*pAllocation)->InitBufferImageUsage(pBufferCreateInfo->usage);
      -
      19103  #endif
      -
      19104  if(pAllocationInfo != VMA_NULL)
      -
      19105  {
      -
      19106  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
      -
      19107  }
      -
      19108 
      -
      19109  return VK_SUCCESS;
      -
      19110  }
      -
      19111  allocator->FreeMemory(
      -
      19112  1, // allocationCount
      -
      19113  pAllocation);
      -
      19114  *pAllocation = VK_NULL_HANDLE;
      -
      19115  (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks());
      -
      19116  *pBuffer = VK_NULL_HANDLE;
      -
      19117  return res;
      -
      19118  }
      -
      19119  (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks());
      -
      19120  *pBuffer = VK_NULL_HANDLE;
      -
      19121  return res;
      -
      19122  }
      -
      19123  return res;
      -
      19124 }
      -
      19125 
      -
      19126 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer(
      -
      19127  VmaAllocator allocator,
      -
      19128  VkBuffer buffer,
      -
      19129  VmaAllocation allocation)
      -
      19130 {
      -
      19131  VMA_ASSERT(allocator);
      -
      19132 
      -
      19133  if(buffer == VK_NULL_HANDLE && allocation == VK_NULL_HANDLE)
      -
      19134  {
      -
      19135  return;
      -
      19136  }
      -
      19137 
      -
      19138  VMA_DEBUG_LOG("vmaDestroyBuffer");
      -
      19139 
      -
      19140  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      19141 
      -
      19142 #if VMA_RECORDING_ENABLED
      -
      19143  if(allocator->GetRecorder() != VMA_NULL)
      -
      19144  {
      -
      19145  allocator->GetRecorder()->RecordDestroyBuffer(
      -
      19146  allocator->GetCurrentFrameIndex(),
      -
      19147  allocation);
      -
      19148  }
      -
      19149 #endif
      -
      19150 
      -
      19151  if(buffer != VK_NULL_HANDLE)
      -
      19152  {
      -
      19153  (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, buffer, allocator->GetAllocationCallbacks());
      -
      19154  }
      +
      19080  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      19081 
      +
      19082  return allocator->CheckCorruption(memoryTypeBits);
      +
      19083 }
      +
      19084 
      +
      19085 VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragment(
      +
      19086  VmaAllocator allocator,
      +
      19087  const VmaAllocation* pAllocations,
      +
      19088  size_t allocationCount,
      +
      19089  VkBool32* pAllocationsChanged,
      +
      19090  const VmaDefragmentationInfo *pDefragmentationInfo,
      +
      19091  VmaDefragmentationStats* pDefragmentationStats)
      +
      19092 {
      +
      19093  // Deprecated interface, reimplemented using new one.
      +
      19094 
      +
      19095  VmaDefragmentationInfo2 info2 = {};
      +
      19096  info2.allocationCount = (uint32_t)allocationCount;
      +
      19097  info2.pAllocations = pAllocations;
      +
      19098  info2.pAllocationsChanged = pAllocationsChanged;
      +
      19099  if(pDefragmentationInfo != VMA_NULL)
      +
      19100  {
      +
      19101  info2.maxCpuAllocationsToMove = pDefragmentationInfo->maxAllocationsToMove;
      +
      19102  info2.maxCpuBytesToMove = pDefragmentationInfo->maxBytesToMove;
      +
      19103  }
      +
      19104  else
      +
      19105  {
      +
      19106  info2.maxCpuAllocationsToMove = UINT32_MAX;
      +
      19107  info2.maxCpuBytesToMove = VK_WHOLE_SIZE;
      +
      19108  }
      +
      19109  // info2.flags, maxGpuAllocationsToMove, maxGpuBytesToMove, commandBuffer deliberately left zero.
      +
      19110 
      + +
      19112  VkResult res = vmaDefragmentationBegin(allocator, &info2, pDefragmentationStats, &ctx);
      +
      19113  if(res == VK_NOT_READY)
      +
      19114  {
      +
      19115  res = vmaDefragmentationEnd( allocator, ctx);
      +
      19116  }
      +
      19117  return res;
      +
      19118 }
      +
      19119 
      +
      19120 VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragmentationBegin(
      +
      19121  VmaAllocator allocator,
      +
      19122  const VmaDefragmentationInfo2* pInfo,
      +
      19123  VmaDefragmentationStats* pStats,
      +
      19124  VmaDefragmentationContext *pContext)
      +
      19125 {
      +
      19126  VMA_ASSERT(allocator && pInfo && pContext);
      +
      19127 
      +
      19128  // Degenerate case: Nothing to defragment.
      +
      19129  if(pInfo->allocationCount == 0 && pInfo->poolCount == 0)
      +
      19130  {
      +
      19131  return VK_SUCCESS;
      +
      19132  }
      +
      19133 
      +
      19134  VMA_ASSERT(pInfo->allocationCount == 0 || pInfo->pAllocations != VMA_NULL);
      +
      19135  VMA_ASSERT(pInfo->poolCount == 0 || pInfo->pPools != VMA_NULL);
      +
      19136  VMA_HEAVY_ASSERT(VmaValidatePointerArray(pInfo->allocationCount, pInfo->pAllocations));
      +
      19137  VMA_HEAVY_ASSERT(VmaValidatePointerArray(pInfo->poolCount, pInfo->pPools));
      +
      19138 
      +
      19139  VMA_DEBUG_LOG("vmaDefragmentationBegin");
      +
      19140 
      +
      19141  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      19142 
      +
      19143  VkResult res = allocator->DefragmentationBegin(*pInfo, pStats, pContext);
      +
      19144 
      +
      19145 #if VMA_RECORDING_ENABLED
      +
      19146  if(allocator->GetRecorder() != VMA_NULL)
      +
      19147  {
      +
      19148  allocator->GetRecorder()->RecordDefragmentationBegin(
      +
      19149  allocator->GetCurrentFrameIndex(), *pInfo, *pContext);
      +
      19150  }
      +
      19151 #endif
      +
      19152 
      +
      19153  return res;
      +
      19154 }
      19155 
      -
      19156  if(allocation != VK_NULL_HANDLE)
      -
      19157  {
      -
      19158  allocator->FreeMemory(
      -
      19159  1, // allocationCount
      -
      19160  &allocation);
      -
      19161  }
      -
      19162 }
      +
      19156 VMA_CALL_PRE VkResult VMA_CALL_POST vmaDefragmentationEnd(
      +
      19157  VmaAllocator allocator,
      +
      19158  VmaDefragmentationContext context)
      +
      19159 {
      +
      19160  VMA_ASSERT(allocator);
      +
      19161 
      +
      19162  VMA_DEBUG_LOG("vmaDefragmentationEnd");
      19163 
      -
      19164 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage(
      -
      19165  VmaAllocator allocator,
      -
      19166  const VkImageCreateInfo* pImageCreateInfo,
      -
      19167  const VmaAllocationCreateInfo* pAllocationCreateInfo,
      -
      19168  VkImage* pImage,
      -
      19169  VmaAllocation* pAllocation,
      -
      19170  VmaAllocationInfo* pAllocationInfo)
      -
      19171 {
      -
      19172  VMA_ASSERT(allocator && pImageCreateInfo && pAllocationCreateInfo && pImage && pAllocation);
      -
      19173 
      -
      19174  if(pImageCreateInfo->extent.width == 0 ||
      -
      19175  pImageCreateInfo->extent.height == 0 ||
      -
      19176  pImageCreateInfo->extent.depth == 0 ||
      -
      19177  pImageCreateInfo->mipLevels == 0 ||
      -
      19178  pImageCreateInfo->arrayLayers == 0)
      +
      19164  if(context != VK_NULL_HANDLE)
      +
      19165  {
      +
      19166  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      19167 
      +
      19168 #if VMA_RECORDING_ENABLED
      +
      19169  if(allocator->GetRecorder() != VMA_NULL)
      +
      19170  {
      +
      19171  allocator->GetRecorder()->RecordDefragmentationEnd(
      +
      19172  allocator->GetCurrentFrameIndex(), context);
      +
      19173  }
      +
      19174 #endif
      +
      19175 
      +
      19176  return allocator->DefragmentationEnd(context);
      +
      19177  }
      +
      19178  else
      19179  {
      -
      19180  return VK_ERROR_VALIDATION_FAILED_EXT;
      +
      19180  return VK_SUCCESS;
      19181  }
      -
      19182 
      -
      19183  VMA_DEBUG_LOG("vmaCreateImage");
      -
      19184 
      -
      19185  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      19186 
      -
      19187  *pImage = VK_NULL_HANDLE;
      -
      19188  *pAllocation = VK_NULL_HANDLE;
      -
      19189 
      -
      19190  // 1. Create VkImage.
      -
      19191  VkResult res = (*allocator->GetVulkanFunctions().vkCreateImage)(
      -
      19192  allocator->m_hDevice,
      -
      19193  pImageCreateInfo,
      -
      19194  allocator->GetAllocationCallbacks(),
      -
      19195  pImage);
      -
      19196  if(res >= 0)
      -
      19197  {
      -
      19198  VmaSuballocationType suballocType = pImageCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL ?
      -
      19199  VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL :
      -
      19200  VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR;
      -
      19201 
      -
      19202  // 2. Allocate memory using allocator.
      -
      19203  VkMemoryRequirements vkMemReq = {};
      -
      19204  bool requiresDedicatedAllocation = false;
      -
      19205  bool prefersDedicatedAllocation = false;
      -
      19206  allocator->GetImageMemoryRequirements(*pImage, vkMemReq,
      -
      19207  requiresDedicatedAllocation, prefersDedicatedAllocation);
      -
      19208 
      -
      19209  res = allocator->AllocateMemory(
      -
      19210  vkMemReq,
      -
      19211  requiresDedicatedAllocation,
      -
      19212  prefersDedicatedAllocation,
      -
      19213  VK_NULL_HANDLE, // dedicatedBuffer
      -
      19214  UINT32_MAX, // dedicatedBufferUsage
      -
      19215  *pImage, // dedicatedImage
      -
      19216  *pAllocationCreateInfo,
      -
      19217  suballocType,
      -
      19218  1, // allocationCount
      -
      19219  pAllocation);
      -
      19220 
      -
      19221 #if VMA_RECORDING_ENABLED
      -
      19222  if(allocator->GetRecorder() != VMA_NULL)
      -
      19223  {
      -
      19224  allocator->GetRecorder()->RecordCreateImage(
      -
      19225  allocator->GetCurrentFrameIndex(),
      -
      19226  *pImageCreateInfo,
      -
      19227  *pAllocationCreateInfo,
      -
      19228  *pAllocation);
      -
      19229  }
      -
      19230 #endif
      -
      19231 
      -
      19232  if(res >= 0)
      -
      19233  {
      -
      19234  // 3. Bind image with memory.
      -
      19235  if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0)
      -
      19236  {
      -
      19237  res = allocator->BindImageMemory(*pAllocation, 0, *pImage, VMA_NULL);
      -
      19238  }
      -
      19239  if(res >= 0)
      -
      19240  {
      -
      19241  // All steps succeeded.
      -
      19242  #if VMA_STATS_STRING_ENABLED
      -
      19243  (*pAllocation)->InitBufferImageUsage(pImageCreateInfo->usage);
      -
      19244  #endif
      -
      19245  if(pAllocationInfo != VMA_NULL)
      -
      19246  {
      -
      19247  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
      -
      19248  }
      +
      19182 }
      +
      19183 
      +
      19184 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentationPass(
      +
      19185  VmaAllocator allocator,
      +
      19186  VmaDefragmentationContext context,
      + +
      19188  )
      +
      19189 {
      +
      19190  VMA_ASSERT(allocator);
      +
      19191  VMA_ASSERT(pInfo);
      +
      19192 
      +
      19193  VMA_DEBUG_LOG("vmaBeginDefragmentationPass");
      +
      19194 
      +
      19195  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      19196 
      +
      19197  if(context == VK_NULL_HANDLE)
      +
      19198  {
      +
      19199  pInfo->moveCount = 0;
      +
      19200  return VK_SUCCESS;
      +
      19201  }
      +
      19202 
      +
      19203  return allocator->DefragmentationPassBegin(pInfo, context);
      +
      19204 }
      +
      19205 VMA_CALL_PRE VkResult VMA_CALL_POST vmaEndDefragmentationPass(
      +
      19206  VmaAllocator allocator,
      +
      19207  VmaDefragmentationContext context)
      +
      19208 {
      +
      19209  VMA_ASSERT(allocator);
      +
      19210 
      +
      19211  VMA_DEBUG_LOG("vmaEndDefragmentationPass");
      +
      19212  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      19213 
      +
      19214  if(context == VK_NULL_HANDLE)
      +
      19215  return VK_SUCCESS;
      +
      19216 
      +
      19217  return allocator->DefragmentationPassEnd(context);
      +
      19218 }
      +
      19219 
      +
      19220 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory(
      +
      19221  VmaAllocator allocator,
      +
      19222  VmaAllocation allocation,
      +
      19223  VkBuffer buffer)
      +
      19224 {
      +
      19225  VMA_ASSERT(allocator && allocation && buffer);
      +
      19226 
      +
      19227  VMA_DEBUG_LOG("vmaBindBufferMemory");
      +
      19228 
      +
      19229  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      19230 
      +
      19231  return allocator->BindBufferMemory(allocation, 0, buffer, VMA_NULL);
      +
      19232 }
      +
      19233 
      +
      19234 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory2(
      +
      19235  VmaAllocator allocator,
      +
      19236  VmaAllocation allocation,
      +
      19237  VkDeviceSize allocationLocalOffset,
      +
      19238  VkBuffer buffer,
      +
      19239  const void* pNext)
      +
      19240 {
      +
      19241  VMA_ASSERT(allocator && allocation && buffer);
      +
      19242 
      +
      19243  VMA_DEBUG_LOG("vmaBindBufferMemory2");
      +
      19244 
      +
      19245  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      19246 
      +
      19247  return allocator->BindBufferMemory(allocation, allocationLocalOffset, buffer, pNext);
      +
      19248 }
      19249 
      -
      19250  return VK_SUCCESS;
      -
      19251  }
      -
      19252  allocator->FreeMemory(
      -
      19253  1, // allocationCount
      -
      19254  pAllocation);
      -
      19255  *pAllocation = VK_NULL_HANDLE;
      -
      19256  (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks());
      -
      19257  *pImage = VK_NULL_HANDLE;
      -
      19258  return res;
      -
      19259  }
      -
      19260  (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks());
      -
      19261  *pImage = VK_NULL_HANDLE;
      -
      19262  return res;
      -
      19263  }
      -
      19264  return res;
      -
      19265 }
      -
      19266 
      -
      19267 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage(
      -
      19268  VmaAllocator allocator,
      -
      19269  VkImage image,
      -
      19270  VmaAllocation allocation)
      -
      19271 {
      -
      19272  VMA_ASSERT(allocator);
      -
      19273 
      -
      19274  if(image == VK_NULL_HANDLE && allocation == VK_NULL_HANDLE)
      -
      19275  {
      -
      19276  return;
      -
      19277  }
      -
      19278 
      -
      19279  VMA_DEBUG_LOG("vmaDestroyImage");
      -
      19280 
      -
      19281  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      -
      19282 
      -
      19283 #if VMA_RECORDING_ENABLED
      -
      19284  if(allocator->GetRecorder() != VMA_NULL)
      -
      19285  {
      -
      19286  allocator->GetRecorder()->RecordDestroyImage(
      -
      19287  allocator->GetCurrentFrameIndex(),
      -
      19288  allocation);
      -
      19289  }
      -
      19290 #endif
      -
      19291 
      -
      19292  if(image != VK_NULL_HANDLE)
      -
      19293  {
      -
      19294  (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, image, allocator->GetAllocationCallbacks());
      -
      19295  }
      -
      19296  if(allocation != VK_NULL_HANDLE)
      -
      19297  {
      -
      19298  allocator->FreeMemory(
      -
      19299  1, // allocationCount
      -
      19300  &allocation);
      -
      19301  }
      -
      19302 }
      -
      19303 
      -
      19304 #endif // #ifdef VMA_IMPLEMENTATION
      +
      19250 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory(
      +
      19251  VmaAllocator allocator,
      +
      19252  VmaAllocation allocation,
      +
      19253  VkImage image)
      +
      19254 {
      +
      19255  VMA_ASSERT(allocator && allocation && image);
      +
      19256 
      +
      19257  VMA_DEBUG_LOG("vmaBindImageMemory");
      +
      19258 
      +
      19259  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      19260 
      +
      19261  return allocator->BindImageMemory(allocation, 0, image, VMA_NULL);
      +
      19262 }
      +
      19263 
      +
      19264 VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory2(
      +
      19265  VmaAllocator allocator,
      +
      19266  VmaAllocation allocation,
      +
      19267  VkDeviceSize allocationLocalOffset,
      +
      19268  VkImage image,
      +
      19269  const void* pNext)
      +
      19270 {
      +
      19271  VMA_ASSERT(allocator && allocation && image);
      +
      19272 
      +
      19273  VMA_DEBUG_LOG("vmaBindImageMemory2");
      +
      19274 
      +
      19275  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      19276 
      +
      19277  return allocator->BindImageMemory(allocation, allocationLocalOffset, image, pNext);
      +
      19278 }
      +
      19279 
      +
      19280 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer(
      +
      19281  VmaAllocator allocator,
      +
      19282  const VkBufferCreateInfo* pBufferCreateInfo,
      +
      19283  const VmaAllocationCreateInfo* pAllocationCreateInfo,
      +
      19284  VkBuffer* pBuffer,
      +
      19285  VmaAllocation* pAllocation,
      +
      19286  VmaAllocationInfo* pAllocationInfo)
      +
      19287 {
      +
      19288  VMA_ASSERT(allocator && pBufferCreateInfo && pAllocationCreateInfo && pBuffer && pAllocation);
      +
      19289 
      +
      19290  if(pBufferCreateInfo->size == 0)
      +
      19291  {
      +
      19292  return VK_ERROR_VALIDATION_FAILED_EXT;
      +
      19293  }
      +
      19294  if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY) != 0 &&
      +
      19295  !allocator->m_UseKhrBufferDeviceAddress)
      +
      19296  {
      +
      19297  VMA_ASSERT(0 && "Creating a buffer with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT is not valid if VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT was not used.");
      +
      19298  return VK_ERROR_VALIDATION_FAILED_EXT;
      +
      19299  }
      +
      19300 
      +
      19301  VMA_DEBUG_LOG("vmaCreateBuffer");
      +
      19302 
      +
      19303  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      19304 
      +
      19305  *pBuffer = VK_NULL_HANDLE;
      +
      19306  *pAllocation = VK_NULL_HANDLE;
      +
      19307 
      +
      19308  // 1. Create VkBuffer.
      +
      19309  VkResult res = (*allocator->GetVulkanFunctions().vkCreateBuffer)(
      +
      19310  allocator->m_hDevice,
      +
      19311  pBufferCreateInfo,
      +
      19312  allocator->GetAllocationCallbacks(),
      +
      19313  pBuffer);
      +
      19314  if(res >= 0)
      +
      19315  {
      +
      19316  // 2. vkGetBufferMemoryRequirements.
      +
      19317  VkMemoryRequirements vkMemReq = {};
      +
      19318  bool requiresDedicatedAllocation = false;
      +
      19319  bool prefersDedicatedAllocation = false;
      +
      19320  allocator->GetBufferMemoryRequirements(*pBuffer, vkMemReq,
      +
      19321  requiresDedicatedAllocation, prefersDedicatedAllocation);
      +
      19322 
      +
      19323  // 3. Allocate memory using allocator.
      +
      19324  res = allocator->AllocateMemory(
      +
      19325  vkMemReq,
      +
      19326  requiresDedicatedAllocation,
      +
      19327  prefersDedicatedAllocation,
      +
      19328  *pBuffer, // dedicatedBuffer
      +
      19329  pBufferCreateInfo->usage, // dedicatedBufferUsage
      +
      19330  VK_NULL_HANDLE, // dedicatedImage
      +
      19331  *pAllocationCreateInfo,
      +
      19332  VMA_SUBALLOCATION_TYPE_BUFFER,
      +
      19333  1, // allocationCount
      +
      19334  pAllocation);
      +
      19335 
      +
      19336 #if VMA_RECORDING_ENABLED
      +
      19337  if(allocator->GetRecorder() != VMA_NULL)
      +
      19338  {
      +
      19339  allocator->GetRecorder()->RecordCreateBuffer(
      +
      19340  allocator->GetCurrentFrameIndex(),
      +
      19341  *pBufferCreateInfo,
      +
      19342  *pAllocationCreateInfo,
      +
      19343  *pAllocation);
      +
      19344  }
      +
      19345 #endif
      +
      19346 
      +
      19347  if(res >= 0)
      +
      19348  {
      +
      19349  // 3. Bind buffer with memory.
      +
      19350  if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0)
      +
      19351  {
      +
      19352  res = allocator->BindBufferMemory(*pAllocation, 0, *pBuffer, VMA_NULL);
      +
      19353  }
      +
      19354  if(res >= 0)
      +
      19355  {
      +
      19356  // All steps succeeded.
      +
      19357  #if VMA_STATS_STRING_ENABLED
      +
      19358  (*pAllocation)->InitBufferImageUsage(pBufferCreateInfo->usage);
      +
      19359  #endif
      +
      19360  if(pAllocationInfo != VMA_NULL)
      +
      19361  {
      +
      19362  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
      +
      19363  }
      +
      19364 
      +
      19365  return VK_SUCCESS;
      +
      19366  }
      +
      19367  allocator->FreeMemory(
      +
      19368  1, // allocationCount
      +
      19369  pAllocation);
      +
      19370  *pAllocation = VK_NULL_HANDLE;
      +
      19371  (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks());
      +
      19372  *pBuffer = VK_NULL_HANDLE;
      +
      19373  return res;
      +
      19374  }
      +
      19375  (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks());
      +
      19376  *pBuffer = VK_NULL_HANDLE;
      +
      19377  return res;
      +
      19378  }
      +
      19379  return res;
      +
      19380 }
      +
      19381 
      +
      19382 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer(
      +
      19383  VmaAllocator allocator,
      +
      19384  VkBuffer buffer,
      +
      19385  VmaAllocation allocation)
      +
      19386 {
      +
      19387  VMA_ASSERT(allocator);
      +
      19388 
      +
      19389  if(buffer == VK_NULL_HANDLE && allocation == VK_NULL_HANDLE)
      +
      19390  {
      +
      19391  return;
      +
      19392  }
      +
      19393 
      +
      19394  VMA_DEBUG_LOG("vmaDestroyBuffer");
      +
      19395 
      +
      19396  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      19397 
      +
      19398 #if VMA_RECORDING_ENABLED
      +
      19399  if(allocator->GetRecorder() != VMA_NULL)
      +
      19400  {
      +
      19401  allocator->GetRecorder()->RecordDestroyBuffer(
      +
      19402  allocator->GetCurrentFrameIndex(),
      +
      19403  allocation);
      +
      19404  }
      +
      19405 #endif
      +
      19406 
      +
      19407  if(buffer != VK_NULL_HANDLE)
      +
      19408  {
      +
      19409  (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, buffer, allocator->GetAllocationCallbacks());
      +
      19410  }
      +
      19411 
      +
      19412  if(allocation != VK_NULL_HANDLE)
      +
      19413  {
      +
      19414  allocator->FreeMemory(
      +
      19415  1, // allocationCount
      +
      19416  &allocation);
      +
      19417  }
      +
      19418 }
      +
      19419 
      +
      19420 VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage(
      +
      19421  VmaAllocator allocator,
      +
      19422  const VkImageCreateInfo* pImageCreateInfo,
      +
      19423  const VmaAllocationCreateInfo* pAllocationCreateInfo,
      +
      19424  VkImage* pImage,
      +
      19425  VmaAllocation* pAllocation,
      +
      19426  VmaAllocationInfo* pAllocationInfo)
      +
      19427 {
      +
      19428  VMA_ASSERT(allocator && pImageCreateInfo && pAllocationCreateInfo && pImage && pAllocation);
      +
      19429 
      +
      19430  if(pImageCreateInfo->extent.width == 0 ||
      +
      19431  pImageCreateInfo->extent.height == 0 ||
      +
      19432  pImageCreateInfo->extent.depth == 0 ||
      +
      19433  pImageCreateInfo->mipLevels == 0 ||
      +
      19434  pImageCreateInfo->arrayLayers == 0)
      +
      19435  {
      +
      19436  return VK_ERROR_VALIDATION_FAILED_EXT;
      +
      19437  }
      +
      19438 
      +
      19439  VMA_DEBUG_LOG("vmaCreateImage");
      +
      19440 
      +
      19441  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      19442 
      +
      19443  *pImage = VK_NULL_HANDLE;
      +
      19444  *pAllocation = VK_NULL_HANDLE;
      +
      19445 
      +
      19446  // 1. Create VkImage.
      +
      19447  VkResult res = (*allocator->GetVulkanFunctions().vkCreateImage)(
      +
      19448  allocator->m_hDevice,
      +
      19449  pImageCreateInfo,
      +
      19450  allocator->GetAllocationCallbacks(),
      +
      19451  pImage);
      +
      19452  if(res >= 0)
      +
      19453  {
      +
      19454  VmaSuballocationType suballocType = pImageCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL ?
      +
      19455  VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL :
      +
      19456  VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR;
      +
      19457 
      +
      19458  // 2. Allocate memory using allocator.
      +
      19459  VkMemoryRequirements vkMemReq = {};
      +
      19460  bool requiresDedicatedAllocation = false;
      +
      19461  bool prefersDedicatedAllocation = false;
      +
      19462  allocator->GetImageMemoryRequirements(*pImage, vkMemReq,
      +
      19463  requiresDedicatedAllocation, prefersDedicatedAllocation);
      +
      19464 
      +
      19465  res = allocator->AllocateMemory(
      +
      19466  vkMemReq,
      +
      19467  requiresDedicatedAllocation,
      +
      19468  prefersDedicatedAllocation,
      +
      19469  VK_NULL_HANDLE, // dedicatedBuffer
      +
      19470  UINT32_MAX, // dedicatedBufferUsage
      +
      19471  *pImage, // dedicatedImage
      +
      19472  *pAllocationCreateInfo,
      +
      19473  suballocType,
      +
      19474  1, // allocationCount
      +
      19475  pAllocation);
      +
      19476 
      +
      19477 #if VMA_RECORDING_ENABLED
      +
      19478  if(allocator->GetRecorder() != VMA_NULL)
      +
      19479  {
      +
      19480  allocator->GetRecorder()->RecordCreateImage(
      +
      19481  allocator->GetCurrentFrameIndex(),
      +
      19482  *pImageCreateInfo,
      +
      19483  *pAllocationCreateInfo,
      +
      19484  *pAllocation);
      +
      19485  }
      +
      19486 #endif
      +
      19487 
      +
      19488  if(res >= 0)
      +
      19489  {
      +
      19490  // 3. Bind image with memory.
      +
      19491  if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0)
      +
      19492  {
      +
      19493  res = allocator->BindImageMemory(*pAllocation, 0, *pImage, VMA_NULL);
      +
      19494  }
      +
      19495  if(res >= 0)
      +
      19496  {
      +
      19497  // All steps succeeded.
      +
      19498  #if VMA_STATS_STRING_ENABLED
      +
      19499  (*pAllocation)->InitBufferImageUsage(pImageCreateInfo->usage);
      +
      19500  #endif
      +
      19501  if(pAllocationInfo != VMA_NULL)
      +
      19502  {
      +
      19503  allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
      +
      19504  }
      +
      19505 
      +
      19506  return VK_SUCCESS;
      +
      19507  }
      +
      19508  allocator->FreeMemory(
      +
      19509  1, // allocationCount
      +
      19510  pAllocation);
      +
      19511  *pAllocation = VK_NULL_HANDLE;
      +
      19512  (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks());
      +
      19513  *pImage = VK_NULL_HANDLE;
      +
      19514  return res;
      +
      19515  }
      +
      19516  (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks());
      +
      19517  *pImage = VK_NULL_HANDLE;
      +
      19518  return res;
      +
      19519  }
      +
      19520  return res;
      +
      19521 }
      +
      19522 
      +
      19523 VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage(
      +
      19524  VmaAllocator allocator,
      +
      19525  VkImage image,
      +
      19526  VmaAllocation allocation)
      +
      19527 {
      +
      19528  VMA_ASSERT(allocator);
      +
      19529 
      +
      19530  if(image == VK_NULL_HANDLE && allocation == VK_NULL_HANDLE)
      +
      19531  {
      +
      19532  return;
      +
      19533  }
      +
      19534 
      +
      19535  VMA_DEBUG_LOG("vmaDestroyImage");
      +
      19536 
      +
      19537  VMA_DEBUG_GLOBAL_MUTEX_LOCK
      +
      19538 
      +
      19539 #if VMA_RECORDING_ENABLED
      +
      19540  if(allocator->GetRecorder() != VMA_NULL)
      +
      19541  {
      +
      19542  allocator->GetRecorder()->RecordDestroyImage(
      +
      19543  allocator->GetCurrentFrameIndex(),
      +
      19544  allocation);
      +
      19545  }
      +
      19546 #endif
      +
      19547 
      +
      19548  if(image != VK_NULL_HANDLE)
      +
      19549  {
      +
      19550  (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, image, allocator->GetAllocationCallbacks());
      +
      19551  }
      +
      19552  if(allocation != VK_NULL_HANDLE)
      +
      19553  {
      +
      19554  allocator->FreeMemory(
      +
      19555  1, // allocationCount
      +
      19556  &allocation);
      +
      19557  }
      +
      19558 }
      +
      19559 
      +
      19560 #endif // #ifdef VMA_IMPLEMENTATION
      Definition: vk_mem_alloc.h:2881
      uint32_t memoryTypeBits
      Bitmask containing one bit set for every memory type acceptable for this allocation.
      Definition: vk_mem_alloc.h:2907
      VmaPool pool
      Pool that this allocation should be created in.
      Definition: vk_mem_alloc.h:2913
      @@ -16102,33 +16364,33 @@ $(function() {
      VkDeviceSize usage
      Estimated current memory usage of the program, in bytes.
      Definition: vk_mem_alloc.h:2643
      VkDeviceSize budget
      Estimated amount of memory available to the program, in bytes.
      Definition: vk_mem_alloc.h:2654
      Represents Opaque object that represents started defragmentation process.
      -
      Parameters for defragmentation.
      Definition: vk_mem_alloc.h:3642
      -
      const VmaPool * pPools
      Either null or pointer to array of pools to be defragmented.
      Definition: vk_mem_alloc.h:3682
      -
      uint32_t allocationCount
      Number of allocations in pAllocations array.
      Definition: vk_mem_alloc.h:3648
      -
      uint32_t maxGpuAllocationsToMove
      Maximum number of allocations that can be moved to a different place using transfers on GPU side,...
      Definition: vk_mem_alloc.h:3702
      -
      VkDeviceSize maxGpuBytesToMove
      Maximum total numbers of bytes that can be copied while moving allocations to different places using ...
      Definition: vk_mem_alloc.h:3697
      -
      VmaDefragmentationFlags flags
      Reserved for future use. Should be 0.
      Definition: vk_mem_alloc.h:3645
      -
      VkBool32 * pAllocationsChanged
      Optional, output. Pointer to array that will be filled with information whether the allocation at cer...
      Definition: vk_mem_alloc.h:3663
      -
      uint32_t poolCount
      Numer of pools in pPools array.
      Definition: vk_mem_alloc.h:3666
      -
      VkCommandBuffer commandBuffer
      Optional. Command buffer where GPU copy commands will be posted.
      Definition: vk_mem_alloc.h:3711
      -
      uint32_t maxCpuAllocationsToMove
      Maximum number of allocations that can be moved to a different place using transfers on CPU side,...
      Definition: vk_mem_alloc.h:3692
      -
      const VmaAllocation * pAllocations
      Pointer to array of allocations that can be defragmented.
      Definition: vk_mem_alloc.h:3657
      -
      VkDeviceSize maxCpuBytesToMove
      Maximum total numbers of bytes that can be copied while moving allocations to different places using ...
      Definition: vk_mem_alloc.h:3687
      -
      Deprecated. Optional configuration parameters to be passed to function vmaDefragment().
      Definition: vk_mem_alloc.h:3733
      -
      uint32_t maxAllocationsToMove
      Maximum number of allocations that can be moved to different place.
      Definition: vk_mem_alloc.h:3743
      -
      VkDeviceSize maxBytesToMove
      Maximum total numbers of bytes that can be copied while moving allocations to different places.
      Definition: vk_mem_alloc.h:3738
      -
      Parameters for incremental defragmentation steps.
      Definition: vk_mem_alloc.h:3724
      -
      uint32_t moveCount
      Definition: vk_mem_alloc.h:3725
      -
      VmaDefragmentationPassMoveInfo * pMoves
      Definition: vk_mem_alloc.h:3726
      -
      Definition: vk_mem_alloc.h:3714
      -
      VkDeviceMemory memory
      Definition: vk_mem_alloc.h:3716
      -
      VkDeviceSize offset
      Definition: vk_mem_alloc.h:3717
      -
      VmaAllocation allocation
      Definition: vk_mem_alloc.h:3715
      -
      Statistics returned by function vmaDefragment().
      Definition: vk_mem_alloc.h:3747
      -
      uint32_t deviceMemoryBlocksFreed
      Number of empty VkDeviceMemory objects that have been released to the system.
      Definition: vk_mem_alloc.h:3755
      -
      VkDeviceSize bytesMoved
      Total number of bytes that have been copied while moving allocations to different places.
      Definition: vk_mem_alloc.h:3749
      -
      VkDeviceSize bytesFreed
      Total number of bytes that have been released to the system by freeing empty VkDeviceMemory objects.
      Definition: vk_mem_alloc.h:3751
      -
      uint32_t allocationsMoved
      Number of allocations that have been moved to different places.
      Definition: vk_mem_alloc.h:3753
      +
      Parameters for defragmentation.
      Definition: vk_mem_alloc.h:3630
      +
      const VmaPool * pPools
      Either null or pointer to array of pools to be defragmented.
      Definition: vk_mem_alloc.h:3670
      +
      uint32_t allocationCount
      Number of allocations in pAllocations array.
      Definition: vk_mem_alloc.h:3636
      +
      uint32_t maxGpuAllocationsToMove
      Maximum number of allocations that can be moved to a different place using transfers on GPU side,...
      Definition: vk_mem_alloc.h:3690
      +
      VkDeviceSize maxGpuBytesToMove
      Maximum total numbers of bytes that can be copied while moving allocations to different places using ...
      Definition: vk_mem_alloc.h:3685
      +
      VmaDefragmentationFlags flags
      Reserved for future use. Should be 0.
      Definition: vk_mem_alloc.h:3633
      +
      VkBool32 * pAllocationsChanged
      Optional, output. Pointer to array that will be filled with information whether the allocation at cer...
      Definition: vk_mem_alloc.h:3651
      +
      uint32_t poolCount
      Numer of pools in pPools array.
      Definition: vk_mem_alloc.h:3654
      +
      VkCommandBuffer commandBuffer
      Optional. Command buffer where GPU copy commands will be posted.
      Definition: vk_mem_alloc.h:3699
      +
      uint32_t maxCpuAllocationsToMove
      Maximum number of allocations that can be moved to a different place using transfers on CPU side,...
      Definition: vk_mem_alloc.h:3680
      +
      const VmaAllocation * pAllocations
      Pointer to array of allocations that can be defragmented.
      Definition: vk_mem_alloc.h:3645
      +
      VkDeviceSize maxCpuBytesToMove
      Maximum total numbers of bytes that can be copied while moving allocations to different places using ...
      Definition: vk_mem_alloc.h:3675
      +
      Deprecated. Optional configuration parameters to be passed to function vmaDefragment().
      Definition: vk_mem_alloc.h:3721
      +
      uint32_t maxAllocationsToMove
      Maximum number of allocations that can be moved to different place.
      Definition: vk_mem_alloc.h:3731
      +
      VkDeviceSize maxBytesToMove
      Maximum total numbers of bytes that can be copied while moving allocations to different places.
      Definition: vk_mem_alloc.h:3726
      +
      Parameters for incremental defragmentation steps.
      Definition: vk_mem_alloc.h:3712
      +
      uint32_t moveCount
      Definition: vk_mem_alloc.h:3713
      +
      VmaDefragmentationPassMoveInfo * pMoves
      Definition: vk_mem_alloc.h:3714
      +
      Definition: vk_mem_alloc.h:3702
      +
      VkDeviceMemory memory
      Definition: vk_mem_alloc.h:3704
      +
      VkDeviceSize offset
      Definition: vk_mem_alloc.h:3705
      +
      VmaAllocation allocation
      Definition: vk_mem_alloc.h:3703
      +
      Statistics returned by function vmaDefragment().
      Definition: vk_mem_alloc.h:3735
      +
      uint32_t deviceMemoryBlocksFreed
      Number of empty VkDeviceMemory objects that have been released to the system.
      Definition: vk_mem_alloc.h:3743
      +
      VkDeviceSize bytesMoved
      Total number of bytes that have been copied while moving allocations to different places.
      Definition: vk_mem_alloc.h:3737
      +
      VkDeviceSize bytesFreed
      Total number of bytes that have been released to the system by freeing empty VkDeviceMemory objects.
      Definition: vk_mem_alloc.h:3739
      +
      uint32_t allocationsMoved
      Number of allocations that have been moved to different places.
      Definition: vk_mem_alloc.h:3741
      Set of callbacks that the library will call for vkAllocateMemory and vkFreeMemory.
      Definition: vk_mem_alloc.h:2224
      void * pUserData
      Optional, can be null.
      Definition: vk_mem_alloc.h:2230
      PFN_vmaAllocateDeviceMemoryFunction pfnAllocate
      Optional, can be null.
      Definition: vk_mem_alloc.h:2226
      @@ -16190,7 +16452,6 @@ $(function() {
      VkResult vmaFindMemoryTypeIndexForImageInfo(VmaAllocator allocator, const VkImageCreateInfo *pImageCreateInfo, const VmaAllocationCreateInfo *pAllocationCreateInfo, uint32_t *pMemoryTypeIndex)
      Helps to find memoryTypeIndex, given VkImageCreateInfo and VmaAllocationCreateInfo.
      void vmaDestroyBuffer(VmaAllocator allocator, VkBuffer buffer, VmaAllocation allocation)
      Destroys Vulkan buffer and frees allocated memory.
      VkResult vmaAllocateMemoryForImage(VmaAllocator allocator, VkImage image, const VmaAllocationCreateInfo *pCreateInfo, VmaAllocation *pAllocation, VmaAllocationInfo *pAllocationInfo)
      Function similar to vmaAllocateMemoryForBuffer().
      -
      VkResult vmaResizeAllocation(VmaAllocator allocator, VmaAllocation allocation, VkDeviceSize newSize)
      Deprecated.
      struct VmaPoolCreateInfo VmaPoolCreateInfo
      Describes parameter of created VmaPool.
      void(VKAPI_PTR * PFN_vmaFreeDeviceMemoryFunction)(VmaAllocator allocator, uint32_t memoryType, VkDeviceMemory memory, VkDeviceSize size, void *pUserData)
      Callback function called before vkFreeMemory.
      Definition: vk_mem_alloc.h:2210
      struct VmaRecordSettings VmaRecordSettings
      Parameters for recording calls to VMA functions. To be used in VmaAllocatorCreateInfo::pRecordSetting...
      @@ -16227,9 +16488,9 @@ $(function() {
      void vmaDestroyPool(VmaAllocator allocator, VmaPool pool)
      Destroys VmaPool object and frees Vulkan device memory.
      VkResult vmaCreatePool(VmaAllocator allocator, const VmaPoolCreateInfo *pCreateInfo, VmaPool *pPool)
      Allocates Vulkan device memory and creates VmaPool object.
      void vmaFreeMemory(VmaAllocator allocator, const VmaAllocation allocation)
      Frees memory previously allocated using vmaAllocateMemory(), vmaAllocateMemoryForBuffer(),...
      -
      VmaDefragmentationFlagBits
      Flags to be used in vmaDefragmentationBegin(). None at the moment. Reserved for future use.
      Definition: vk_mem_alloc.h:3632
      -
      @ VMA_DEFRAGMENTATION_FLAG_INCREMENTAL
      Definition: vk_mem_alloc.h:3633
      -
      @ VMA_DEFRAGMENTATION_FLAG_BITS_MAX_ENUM
      Definition: vk_mem_alloc.h:3634
      +
      VmaDefragmentationFlagBits
      Flags to be used in vmaDefragmentationBegin(). None at the moment. Reserved for future use.
      Definition: vk_mem_alloc.h:3620
      +
      @ VMA_DEFRAGMENTATION_FLAG_INCREMENTAL
      Definition: vk_mem_alloc.h:3621
      +
      @ VMA_DEFRAGMENTATION_FLAG_BITS_MAX_ENUM
      Definition: vk_mem_alloc.h:3622
      VkResult vmaBindBufferMemory(VmaAllocator allocator, VmaAllocation allocation, VkBuffer buffer)
      Binds buffer to allocation.
      struct VmaDefragmentationPassInfo VmaDefragmentationPassInfo
      Parameters for incremental defragmentation steps.
      void vmaMakePoolAllocationsLost(VmaAllocator allocator, VmaPool pool, size_t *pLostAllocationCount)
      Marks all allocations in given pool as lost if they are not used in current frame or VmaPoolCreateInf...
      @@ -16240,7 +16501,7 @@ $(function() {
      void vmaGetAllocationInfo(VmaAllocator allocator, VmaAllocation allocation, VmaAllocationInfo *pAllocationInfo)
      Returns current information about specified allocation and atomically marks it as used in current fra...
      void vmaGetMemoryTypeProperties(VmaAllocator allocator, uint32_t memoryTypeIndex, VkMemoryPropertyFlags *pFlags)
      Given Memory Type Index, returns Property Flags of this memory type.
      VkResult vmaDefragmentationEnd(VmaAllocator allocator, VmaDefragmentationContext context)
      Ends defragmentation process.
      -
      VkFlags VmaDefragmentationFlags
      Definition: vk_mem_alloc.h:3636
      +
      VkFlags VmaDefragmentationFlags
      Definition: vk_mem_alloc.h:3624
      VkResult vmaBindBufferMemory2(VmaAllocator allocator, VmaAllocation allocation, VkDeviceSize allocationLocalOffset, VkBuffer buffer, const void *pNext)
      Binds buffer to allocation with additional parameters.
      VmaPoolCreateFlagBits
      Flags to be passed as VmaPoolCreateInfo::flags.
      Definition: vk_mem_alloc.h:2989
      @ VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT
      Enables alternative, linear allocation algorithm in this pool.
      Definition: vk_mem_alloc.h:3024