vk_mem_alloc.h 274 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513
  1. //
  2. // Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #ifndef AMD_VULKAN_MEMORY_ALLOCATOR_H
  23. #define AMD_VULKAN_MEMORY_ALLOCATOR_H
  24. #ifdef __cplusplus
  25. extern "C" {
  26. #endif
  27. /** \mainpage Vulkan Memory Allocator
  28. <b>Version 2.0.0-alpha.6</b> (2017-11-13)
  29. Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. \n
  30. License: MIT
  31. Documentation of all members: vk_mem_alloc.h
  32. Table of contents:
  33. - User guide
  34. - \subpage quick_start
  35. - \subpage choosing_memory_type
  36. - \subpage memory_mapping
  37. - \subpage custom_memory_pools
  38. - \subpage defragmentation
  39. - \subpage lost_allocations
  40. - \subpage allocation_annotation
  41. - \subpage configuration
  42. - \subpage vk_khr_dedicated_allocation
  43. - \subpage thread_safety
  44. See also:
  45. - [Source repository on GitHub](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator)
  46. - [Product page on GPUOpen](https://gpuopen.com/gaming-product/vulkan-memory-allocator/)
  47. \page quick_start Quick start
  48. \section project_setup Project setup
  49. In your project code:
  50. -# Include "vk_mem_alloc.h" file wherever you want to use the library.
  51. -# In exacly one C++ file define following macro before include to build library
  52. implementation.
  53. \code
  54. #define VMA_IMPLEMENTATION
  55. #include "vk_mem_alloc.h"
  56. \endcode
  57. \section initialization Initialization
  58. At program startup:
  59. -# Initialize Vulkan to have `VkPhysicalDevice` and `VkDevice` object.
  60. -# Fill VmaAllocatorCreateInfo structure and create `VmaAllocator` object by
  61. calling vmaCreateAllocator().
  62. \code
  63. VmaAllocatorCreateInfo allocatorInfo = {};
  64. allocatorInfo.physicalDevice = physicalDevice;
  65. allocatorInfo.device = device;
  66. VmaAllocator allocator;
  67. vmaCreateAllocator(&allocatorInfo, &allocator);
  68. \endcode
  69. \section resource_allocation Resource allocation
  70. When you want to create a buffer or image:
  71. -# Fill `VkBufferCreateInfo` / `VkImageCreateInfo` structure.
  72. -# Fill VmaAllocationCreateInfo structure.
  73. -# Call vmaCreateBuffer() / vmaCreateImage() to get `VkBuffer`/`VkImage` with memory
  74. already allocated and bound to it.
  75. \code
  76. VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
  77. bufferInfo.size = 65536;
  78. bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
  79. VmaAllocationCreateInfo allocInfo = {};
  80. allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
  81. VkBuffer buffer;
  82. VmaAllocation allocation;
  83. vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr);
  84. \endcode
  85. Don't forget to destroy your objects when no longer needed:
  86. \code
  87. vmaDestroyBuffer(allocator, buffer, allocation);
  88. vmaDestroyAllocator(allocator);
  89. \endcode
  90. \page choosing_memory_type Choosing memory type
  91. Physical devices in Vulkan support various combinations of memory heaps and
  92. types. Help with choosing correct and optimal memory type for your specific
  93. resource is one of the key features of this library. You can use it by filling
  94. appropriate members of VmaAllocationCreateInfo structure, as described below.
  95. You can also combine multiple methods.
  96. -# If you just want to find memory type index that meets your requirements, you
  97. can use function vmaFindMemoryTypeIndex().
  98. -# If you want to allocate a region of device memory without association with any
  99. specific image or buffer, you can use function vmaAllocateMemory(). Usage of
  100. this function is not recommended and usually not needed.
  101. -# If you already have a buffer or an image created, you want to allocate memory
  102. for it and then you will bind it yourself, you can use function
  103. vmaAllocateMemoryForBuffer(), vmaAllocateMemoryForImage().
  104. -# If you want to create a buffer or an image, allocate memory for it and bind
  105. them together, all in one call, you can use function vmaCreateBuffer(),
  106. vmaCreateImage(). This is the recommended way to use this library.
  107. When using 3. or 4., the library internally queries Vulkan for memory types
  108. supported for that buffer or image (function `vkGetBufferMemoryRequirements()`)
  109. and uses only one of these types.
  110. If no memory type can be found that meets all the requirements, these functions
  111. return `VK_ERROR_FEATURE_NOT_PRESENT`.
  112. You can leave VmaAllocationCreateInfo structure completely filled with zeros.
  113. It means no requirements are specified for memory type.
  114. It is valid, although not very useful.
  115. \section choosing_memory_type_usage Usage
  116. The easiest way to specify memory requirements is to fill member
  117. VmaAllocationCreateInfo::usage using one of the values of enum `VmaMemoryUsage`.
  118. It defines high level, common usage types.
  119. For example, if you want to create a uniform buffer that will be filled using
  120. transfer only once or infrequently and used for rendering every frame, you can
  121. do it using following code:
  122. \code
  123. VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
  124. bufferInfo.size = 65536;
  125. bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
  126. VmaAllocationCreateInfo allocInfo = {};
  127. allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
  128. VkBuffer buffer;
  129. VmaAllocation allocation;
  130. vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr);
  131. \endcode
  132. \section choosing_memory_type_required_preferred_flags Required and preferred flags
  133. You can specify more detailed requirements by filling members
  134. VmaAllocationCreateInfo::requiredFlags and VmaAllocationCreateInfo::preferredFlags
  135. with a combination of bits from enum `VkMemoryPropertyFlags`. For example,
  136. if you want to create a buffer that will be persistently mapped on host (so it
  137. must be `HOST_VISIBLE`) and preferably will also be `HOST_COHERENT` and `HOST_CACHED`,
  138. use following code:
  139. \code
  140. VmaAllocationCreateInfo allocInfo = {};
  141. allocInfo.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
  142. allocInfo.preferredFlags = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
  143. allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
  144. VkBuffer buffer;
  145. VmaAllocation allocation;
  146. vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr);
  147. \endcode
  148. A memory type is chosen that has all the required flags and as many preferred
  149. flags set as possible.
  150. If you use VmaAllocationCreateInfo::usage, it is just internally converted to
  151. a set of required and preferred flags.
  152. \section choosing_memory_type_explicit_memory_types Explicit memory types
  153. If you inspected memory types available on the physical device and you have
  154. a preference for memory types that you want to use, you can fill member
  155. VmaAllocationCreateInfo::memoryTypeBits. It is a bit mask, where each bit set
  156. means that a memory type with that index is allowed to be used for the
  157. allocation. Special value 0, just like UINT32_MAX, means there are no
  158. restrictions to memory type index.
  159. Please note that this member is NOT just a memory type index.
  160. Still you can use it to choose just one, specific memory type.
  161. For example, if you already determined that your buffer should be created in
  162. memory type 2, use following code:
  163. \code
  164. uint32_t memoryTypeIndex = 2;
  165. VmaAllocationCreateInfo allocInfo = {};
  166. allocInfo.memoryTypeBits = 1u << memoryTypeIndex;
  167. VkBuffer buffer;
  168. VmaAllocation allocation;
  169. vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr);
  170. \endcode
  171. \section choosing_memory_type_custom_memory_pools Custom memory pools
  172. If you allocate from custom memory pool, all the ways of specifying memory
  173. requirements described above are not applicable and the aforementioned members
  174. of VmaAllocationCreateInfo structure are ignored. Memory type is selected
  175. explicitly when creating the pool and then used to make all the allocations from
  176. that pool. For further details, see \ref custom_memory_pools.
  177. \page memory_mapping Memory mapping
  178. \section persistently_mapped_memory Persistently mapped memory
  179. If you need to map memory on host, it may happen that two allocations are
  180. assigned to the same `VkDeviceMemory` block, so if you map them both at the same
  181. time, it will cause error because mapping single memory block multiple times is
  182. illegal in Vulkan.
  183. TODO update this...
  184. It is safer, more convenient and more efficient to use special feature designed
  185. for that: persistently mapped memory. Allocations made with
  186. `VMA_ALLOCATION_CREATE_MAPPED_BIT` flag set in
  187. VmaAllocationCreateInfo::flags are returned from device memory
  188. blocks that stay mapped all the time, so you can just access CPU pointer to it.
  189. VmaAllocationInfo::pMappedData pointer is already offseted to the beginning of
  190. particular allocation. Example:
  191. \code
  192. VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
  193. bufCreateInfo.size = 1024;
  194. bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
  195. VmaAllocationCreateInfo allocCreateInfo = {};
  196. allocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
  197. allocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
  198. VkBuffer buf;
  199. VmaAllocation alloc;
  200. VmaAllocationInfo allocInfo;
  201. vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo);
  202. // Buffer is immediately mapped. You can access its memory.
  203. memcpy(allocInfo.pMappedData, myData, 1024);
  204. \endcode
  205. Memory in Vulkan doesn't need to be unmapped before using it e.g. for transfers,
  206. but if you are not sure whether it's `HOST_COHERENT` (here is surely is because
  207. it's created with `VMA_MEMORY_USAGE_CPU_ONLY`), you should check it. If it's
  208. not, you should call `vkInvalidateMappedMemoryRanges()` before reading and
  209. `vkFlushMappedMemoryRanges()` after writing to mapped memory on CPU. Example:
  210. \code
  211. VkMemoryPropertyFlags memFlags;
  212. vmaGetMemoryTypeProperties(allocator, allocInfo.memoryType, &memFlags);
  213. if((memFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0)
  214. {
  215. VkMappedMemoryRange memRange = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE };
  216. memRange.memory = allocInfo.deviceMemory;
  217. memRange.offset = allocInfo.offset;
  218. memRange.size = allocInfo.size;
  219. vkFlushMappedMemoryRanges(device, 1, &memRange);
  220. }
  221. \endcode
  222. \section amd_perf_note Note on performance
  223. There is a situation that you should be careful about. It happens only if all of
  224. following conditions are met:
  225. -# You use AMD GPU.
  226. -# You use the memory type that is both `DEVICE_LOCAL` and `HOST_VISIBLE`
  227. (used when you specify `VMA_MEMORY_USAGE_CPU_TO_GPU`).
  228. -# Operating system is Windows 7 or 8.x (Windows 10 is not affected because it
  229. uses WDDM2).
  230. Then whenever a `VkDeviceMemory` block allocated from this memory type is mapped
  231. for the time of any call to `vkQueueSubmit()` or `vkQueuePresentKHR()`, this
  232. block is migrated by WDDM to system RAM, which degrades performance. It doesn't
  233. matter if that particular memory block is actually used by the command buffer
  234. being submitted.
  235. To avoid this problem, either make sure to unmap all allocations made from this
  236. memory type before your Submit and Present, or use `VMA_MEMORY_USAGE_GPU_ONLY`
  237. and transfer from a staging buffer in `VMA_MEMORY_USAGE_CPU_ONLY`, which can
  238. safely stay mapped all the time.
  239. \page custom_memory_pools Custom memory pools
  240. The library automatically creates and manages default memory pool for each
  241. memory type available on the device. A pool contains a number of
  242. `VkDeviceMemory` blocks. You can create custom pool and allocate memory out of
  243. it. It can be useful if you want to:
  244. - Keep certain kind of allocations separate from others.
  245. - Enforce particular size of Vulkan memory blocks.
  246. - Limit maximum amount of Vulkan memory allocated for that pool.
  247. To use custom memory pools:
  248. -# Fill VmaPoolCreateInfo structure.
  249. -# Call vmaCreatePool() to obtain `VmaPool` handle.
  250. -# When making an allocation, set VmaAllocationCreateInfo::pool to this handle.
  251. You don't need to specify any other parameters of this structure, like usage.
  252. Example:
  253. \code
  254. // Create a pool that could have at most 2 blocks, 128 MB each.
  255. VmaPoolCreateInfo poolCreateInfo = {};
  256. poolCreateInfo.memoryTypeIndex = ...
  257. poolCreateInfo.blockSize = 128ull * 1024 * 1024;
  258. poolCreateInfo.maxBlockCount = 2;
  259. VmaPool pool;
  260. vmaCreatePool(allocator, &poolCreateInfo, &pool);
  261. // Allocate a buffer out of it.
  262. VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
  263. bufCreateInfo.size = 1024;
  264. bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
  265. VmaAllocationCreateInfo allocCreateInfo = {};
  266. allocCreateInfo.pool = pool;
  267. VkBuffer buf;
  268. VmaAllocation alloc;
  269. VmaAllocationInfo allocInfo;
  270. vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo);
  271. \endcode
  272. You have to free all allocations made from this pool before destroying it.
  273. \code
  274. vmaDestroyBuffer(allocator, buf, alloc);
  275. vmaDestroyPool(allocator, pool);
  276. \endcode
  277. \page defragmentation Defragmentation
  278. Interleaved allocations and deallocations of many objects of varying size can
  279. cause fragmentation, which can lead to a situation where the library is unable
  280. to find a continuous range of free memory for a new allocation despite there is
  281. enough free space, just scattered across many small free ranges between existing
  282. allocations.
  283. To mitigate this problem, you can use vmaDefragment(). Given set of allocations,
  284. this function can move them to compact used memory, ensure more continuous free
  285. space and possibly also free some `VkDeviceMemory`. It can work only on
  286. allocations made from memory type that is `HOST_VISIBLE`. Allocations are
  287. modified to point to the new `VkDeviceMemory` and offset. Data in this memory is
  288. also `memmove`-ed to the new place. However, if you have images or buffers bound
  289. to these allocations (and you certainly do), you need to destroy, recreate, and
  290. bind them to the new place in memory.
  291. For further details and example code, see documentation of function
  292. vmaDefragment().
  293. \page lost_allocations Lost allocations
  294. If your game oversubscribes video memory, if may work OK in previous-generation
  295. graphics APIs (DirectX 9, 10, 11, OpenGL) because resources are automatically
  296. paged to system RAM. In Vulkan you can't do it because when you run out of
  297. memory, an allocation just fails. If you have more data (e.g. textures) that can
  298. fit into VRAM and you don't need it all at once, you may want to upload them to
  299. GPU on demand and "push out" ones that are not used for a long time to make room
  300. for the new ones, effectively using VRAM (or a cartain memory pool) as a form of
  301. cache. Vulkan Memory Allocator can help you with that by supporting a concept of
  302. "lost allocations".
  303. To create an allocation that can become lost, include `VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT`
  304. flag in VmaAllocationCreateInfo::flags. Before using a buffer or image bound to
  305. such allocation in every new frame, you need to query it if it's not lost. To
  306. check it: call vmaGetAllocationInfo() and see if VmaAllocationInfo::deviceMemory
  307. is not `VK_NULL_HANDLE`. If the allocation is lost, you should not use it or
  308. buffer/image bound to it. You mustn't forget to destroy this allocation and this
  309. buffer/image.
  310. To create an allocation that can make some other allocations lost to make room
  311. for it, use `VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT` flag. You will
  312. usually use both flags `VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT` and
  313. `VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT` at the same time.
  314. Warning! Current implementation uses quite naive, brute force algorithm,
  315. which can make allocation calls that use `VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT`
  316. flag quite slow. A new, more optimal algorithm and data structure to speed this
  317. up is planned for the future.
  318. <b>When interleaving creation of new allocations with usage of existing ones,
  319. how do you make sure that an allocation won't become lost while it's used in the
  320. current frame?</b>
  321. It is ensured because vmaGetAllocationInfo() not only returns allocation
  322. parameters and checks whether it's not lost, but when it's not, it also
  323. atomically marks it as used in the current frame, which makes it impossible to
  324. become lost in that frame. It uses lockless algorithm, so it works fast and
  325. doesn't involve locking any internal mutex.
  326. <b>What if my allocation may still be in use by the GPU when it's rendering a
  327. previous frame while I already submit new frame on the CPU?</b>
  328. You can make sure that allocations "touched" by vmaGetAllocationInfo() will not
  329. become lost for a number of additional frames back from the current one by
  330. specifying this number as VmaAllocatorCreateInfo::frameInUseCount (for default
  331. memory pool) and VmaPoolCreateInfo::frameInUseCount (for custom pool).
  332. <b>How do you inform the library when new frame starts?</b>
  333. You need to call function vmaSetCurrentFrameIndex().
  334. Example code:
  335. \code
  336. struct MyBuffer
  337. {
  338. VkBuffer m_Buf = nullptr;
  339. VmaAllocation m_Alloc = nullptr;
  340. // Called when the buffer is really needed in the current frame.
  341. void EnsureBuffer();
  342. };
  343. void MyBuffer::EnsureBuffer()
  344. {
  345. // Buffer has been created.
  346. if(m_Buf != VK_NULL_HANDLE)
  347. {
  348. // Check if its allocation is not lost + mark it as used in current frame.
  349. VmaAllocationInfo allocInfo;
  350. vmaGetAllocationInfo(allocator, m_Alloc, &allocInfo);
  351. if(allocInfo.deviceMemory != VK_NULL_HANDLE)
  352. {
  353. // It's all OK - safe to use m_Buf.
  354. return;
  355. }
  356. }
  357. // Buffer not yet exists or lost - destroy and recreate it.
  358. vmaDestroyBuffer(allocator, m_Buf, m_Alloc);
  359. VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
  360. bufCreateInfo.size = 1024;
  361. bufCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
  362. VmaAllocationCreateInfo allocCreateInfo = {};
  363. allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
  364. allocCreateInfo.flags = VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT |
  365. VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT;
  366. vmaCreateBuffer(allocator, &bufCreateInfo, &allocCreateInfo, &m_Buf, &m_Alloc, nullptr);
  367. }
  368. \endcode
  369. When using lost allocations, you may see some Vulkan validation layer warnings
  370. about overlapping regions of memory bound to different kinds of buffers and
  371. images. This is still valid as long as you implement proper handling of lost
  372. allocations (like in the example above) and don't use them.
  373. The library uses following algorithm for allocation, in order:
  374. -# Try to find free range of memory in existing blocks.
  375. -# If failed, try to create a new block of `VkDeviceMemory`, with preferred block size.
  376. -# If failed, try to create such block with size/2 and size/4.
  377. -# If failed and `VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT` flag was
  378. specified, try to find space in existing blocks, possilby making some other
  379. allocations lost.
  380. -# If failed, try to allocate separate `VkDeviceMemory` for this allocation,
  381. just like when you use `VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT`.
  382. -# If failed, choose other memory type that meets the requirements specified in
  383. VmaAllocationCreateInfo and go to point 1.
  384. -# If failed, return `VK_ERROR_OUT_OF_DEVICE_MEMORY`.
  385. \page allocation_annotation Allocation names and user data
  386. \section allocation_user_data Allocation user data
  387. You can annotate allocations with your own information, e.g. for debugging purposes.
  388. To do that, fill VmaAllocationCreateInfo::pUserData field when creating
  389. an allocation. It's an opaque `void*` pointer. You can use it e.g. as a pointer,
  390. some handle, index, key, ordinal number or any other value that would associate
  391. the allocation with your custom metadata.
  392. \code
  393. VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
  394. // Fill bufferInfo...
  395. MyBufferMetadata* pMetadata = CreateBufferMetadata();
  396. VmaAllocationCreateInfo allocCreateInfo = {};
  397. allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
  398. allocCreateInfo.pUserData = pMetadata;
  399. VkBuffer buffer;
  400. VmaAllocation allocation;
  401. vmaCreateBuffer(allocator, &bufferInfo, &allocCreateInfo, &buffer, &allocation, nullptr);
  402. \endcode
  403. The pointer may be later retrieved as VmaAllocationInfo::pUserData:
  404. \code
  405. VmaAllocationInfo allocInfo;
  406. vmaGetAllocationInfo(allocator, allocation, &allocInfo);
  407. MyBufferMetadata* pMetadata = (MyBufferMetadata*)allocInfo.pUserData;
  408. \endcode
  409. It can also be changed using function vmaSetAllocationUserData().
  410. Values of (non-zero) allocations' `pUserData` are printed in JSON report created by
  411. vmaBuildStatsString(), in hexadecimal form.
  412. \section allocation_names Allocation names
  413. There is alternative mode available where `pUserData` pointer is used to point to
  414. a null-terminated string, giving a name to the allocation. To use this mode,
  415. set `VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT` flag in VmaAllocationCreateInfo::flags.
  416. Then `pUserData` passed as VmaAllocationCreateInfo::pUserData or argument to
  417. vmaSetAllocationUserData() must be either null or pointer to a null-terminated string.
  418. The library creates internal copy of the string, so the pointer you pass doesn't need
  419. to be valid for whole lifetime of the allocation. You can free it after the call.
  420. \code
  421. VkImageCreateInfo imageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
  422. // Fill imageInfo...
  423. std::string imageName = "Texture: ";
  424. imageName += fileName;
  425. VmaAllocationCreateInfo allocCreateInfo = {};
  426. allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
  427. allocCreateInfo.flags = VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT;
  428. allocCreateInfo.pUserData = imageName.c_str();
  429. VkImage image;
  430. VmaAllocation allocation;
  431. vmaCreateImage(allocator, &imageInfo, &allocCreateInfo, &image, &allocation, nullptr);
  432. \endcode
  433. The value of `pUserData` pointer of the allocation will be different than the one
  434. you passed when setting allocation's name - pointing to a buffer managed
  435. internally that holds copy of the string.
  436. \code
  437. VmaAllocationInfo allocInfo;
  438. vmaGetAllocationInfo(allocator, allocation, &allocInfo);
  439. const char* imageName = (const char*)allocInfo.pUserData;
  440. printf("Image name: %s\n", imageName);
  441. \endcode
  442. That string is also printed in JSON report created by vmaBuildStatsString().
  443. \page configuration Configuration
  444. Please check "CONFIGURATION SECTION" in the code to find macros that you can define
  445. before each include of this file or change directly in this file to provide
  446. your own implementation of basic facilities like assert, `min()` and `max()` functions,
  447. mutex etc. C++ STL is used by default, but changing these allows you to get rid
  448. of any STL usage if you want, as many game developers tend to do.
  449. \section config_Vulkan_functions Pointers to Vulkan functions
  450. The library uses Vulkan functions straight from the `vulkan.h` header by default.
  451. If you want to provide your own pointers to these functions, e.g. fetched using
  452. `vkGetInstanceProcAddr()` and `vkGetDeviceProcAddr()`:
  453. -# Define `VMA_STATIC_VULKAN_FUNCTIONS 0`.
  454. -# Provide valid pointers through VmaAllocatorCreateInfo::pVulkanFunctions.
  455. \section custom_memory_allocator Custom host memory allocator
  456. If you use custom allocator for CPU memory rather than default operator `new`
  457. and `delete` from C++, you can make this library using your allocator as well
  458. by filling optional member VmaAllocatorCreateInfo::pAllocationCallbacks. These
  459. functions will be passed to Vulkan, as well as used by the library itself to
  460. make any CPU-side allocations.
  461. \section allocation_callbacks Device memory allocation callbacks
  462. The library makes calls to `vkAllocateMemory()` and `vkFreeMemory()` internally.
  463. You can setup callbacks to be informed about these calls, e.g. for the purpose
  464. of gathering some statistics. To do it, fill optional member
  465. VmaAllocatorCreateInfo::pDeviceMemoryCallbacks.
  466. \section heap_memory_limit Device heap memory limit
  467. If you want to test how your program behaves with limited amount of Vulkan device
  468. memory available without switching your graphics card to one that really has
  469. smaller VRAM, you can use a feature of this library intended for this purpose.
  470. To do it, fill optional member VmaAllocatorCreateInfo::pHeapSizeLimit.
  471. \page vk_khr_dedicated_allocation VK_KHR_dedicated_allocation
  472. VK_KHR_dedicated_allocation is a Vulkan extension which can be used to improve
  473. performance on some GPUs. It augments Vulkan API with possibility to query
  474. driver whether it prefers particular buffer or image to have its own, dedicated
  475. allocation (separate `VkDeviceMemory` block) for better efficiency - to be able
  476. to do some internal optimizations.
  477. The extension is supported by this library. It will be used automatically when
  478. enabled. To enable it:
  479. 1 . When creating Vulkan device, check if following 2 device extensions are
  480. supported (call `vkEnumerateDeviceExtensionProperties()`).
  481. If yes, enable them (fill `VkDeviceCreateInfo::ppEnabledExtensionNames`).
  482. - VK_KHR_get_memory_requirements2
  483. - VK_KHR_dedicated_allocation
  484. If you enabled these extensions:
  485. 2 . Use `VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT` flag when creating
  486. your `VmaAllocator` to inform the library that you enabled required extensions
  487. and you want the library to use them.
  488. \code
  489. allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT;
  490. vmaCreateAllocator(&allocatorInfo, &allocator);
  491. \endcode
  492. That's all. The extension will be automatically used whenever you create a
  493. buffer using vmaCreateBuffer() or image using vmaCreateImage().
  494. When using the extension together with Vulkan Validation Layer, you will receive
  495. warnings like this:
  496. vkBindBufferMemory(): Binding memory to buffer 0x33 but vkGetBufferMemoryRequirements() has not been called on that buffer.
  497. It is OK, you should just ignore it. It happens because you use function
  498. `vkGetBufferMemoryRequirements2KHR()` instead of standard
  499. `vkGetBufferMemoryRequirements()`, while the validation layer seems to be
  500. unaware of it.
  501. To learn more about this extension, see:
  502. - [VK_KHR_dedicated_allocation in Vulkan specification](https://www.khronos.org/registry/vulkan/specs/1.0-extensions/html/vkspec.html#VK_KHR_dedicated_allocation)
  503. - [VK_KHR_dedicated_allocation unofficial manual](http://asawicki.info/articles/VK_KHR_dedicated_allocation.php5)
  504. \page thread_safety Thread safety
  505. - The library has no global state, so separate `VmaAllocator` objects can be used
  506. independently.
  507. - By default, all calls to functions that take `VmaAllocator` as first parameter
  508. are safe to call from multiple threads simultaneously because they are
  509. synchronized internally when needed.
  510. - When the allocator is created with `VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT`
  511. flag, calls to functions that take such `VmaAllocator` object must be
  512. synchronized externally.
  513. - Access to a `VmaAllocation` object must be externally synchronized. For example,
  514. you must not call vmaGetAllocationInfo() and vmaMapMemory() from different
  515. threads at the same time if you pass the same `VmaAllocation` object to these
  516. functions.
  517. */
  518. #include <vulkan/vulkan.h>
  519. VK_DEFINE_HANDLE(VmaAllocator)
  520. /// Callback function called after successful vkAllocateMemory.
  521. typedef void (VKAPI_PTR *PFN_vmaAllocateDeviceMemoryFunction)(
  522. VmaAllocator allocator,
  523. uint32_t memoryType,
  524. VkDeviceMemory memory,
  525. VkDeviceSize size);
  526. /// Callback function called before vkFreeMemory.
  527. typedef void (VKAPI_PTR *PFN_vmaFreeDeviceMemoryFunction)(
  528. VmaAllocator allocator,
  529. uint32_t memoryType,
  530. VkDeviceMemory memory,
  531. VkDeviceSize size);
  532. /** \brief Set of callbacks that the library will call for `vkAllocateMemory` and `vkFreeMemory`.
  533. Provided for informative purpose, e.g. to gather statistics about number of
  534. allocations or total amount of memory allocated in Vulkan.
  535. Used in VmaAllocatorCreateInfo::pDeviceMemoryCallbacks.
  536. */
  537. typedef struct VmaDeviceMemoryCallbacks {
  538. /// Optional, can be null.
  539. PFN_vmaAllocateDeviceMemoryFunction pfnAllocate;
  540. /// Optional, can be null.
  541. PFN_vmaFreeDeviceMemoryFunction pfnFree;
  542. } VmaDeviceMemoryCallbacks;
  543. /// Flags for created VmaAllocator.
  544. typedef enum VmaAllocatorCreateFlagBits {
  545. /** \brief Allocator and all objects created from it will not be synchronized internally, so you must guarantee they are used from only one thread at a time or synchronized externally by you.
  546. Using this flag may increase performance because internal mutexes are not used.
  547. */
  548. VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT = 0x00000001,
  549. /** \brief Enables usage of VK_KHR_dedicated_allocation extension.
  550. Using this extenion will automatically allocate dedicated blocks of memory for
  551. some buffers and images instead of suballocating place for them out of bigger
  552. memory blocks (as if you explicitly used VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT
  553. flag) when it is recommended by the driver. It may improve performance on some
  554. GPUs.
  555. You may set this flag only if you found out that following device extensions are
  556. supported, you enabled them while creating Vulkan device passed as
  557. VmaAllocatorCreateInfo::device, and you want them to be used internally by this
  558. library:
  559. - VK_KHR_get_memory_requirements2
  560. - VK_KHR_dedicated_allocation
  561. When this flag is set, you can experience following warnings reported by Vulkan
  562. validation layer. You can ignore them.
  563. > vkBindBufferMemory(): Binding memory to buffer 0x2d but vkGetBufferMemoryRequirements() has not been called on that buffer.
  564. */
  565. VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT = 0x00000002,
  566. VMA_ALLOCATOR_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
  567. } VmaAllocatorCreateFlagBits;
  568. typedef VkFlags VmaAllocatorCreateFlags;
  569. /** \brief Pointers to some Vulkan functions - a subset used by the library.
  570. Used in VmaAllocatorCreateInfo::pVulkanFunctions.
  571. */
  572. typedef struct VmaVulkanFunctions {
  573. PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties;
  574. PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties;
  575. PFN_vkAllocateMemory vkAllocateMemory;
  576. PFN_vkFreeMemory vkFreeMemory;
  577. PFN_vkMapMemory vkMapMemory;
  578. PFN_vkUnmapMemory vkUnmapMemory;
  579. PFN_vkBindBufferMemory vkBindBufferMemory;
  580. PFN_vkBindImageMemory vkBindImageMemory;
  581. PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements;
  582. PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements;
  583. PFN_vkCreateBuffer vkCreateBuffer;
  584. PFN_vkDestroyBuffer vkDestroyBuffer;
  585. PFN_vkCreateImage vkCreateImage;
  586. PFN_vkDestroyImage vkDestroyImage;
  587. PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR;
  588. PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR;
  589. } VmaVulkanFunctions;
  590. /// Description of a Allocator to be created.
  591. typedef struct VmaAllocatorCreateInfo
  592. {
  593. /// Flags for created allocator. Use VmaAllocatorCreateFlagBits enum.
  594. VmaAllocatorCreateFlags flags;
  595. /// Vulkan physical device.
  596. /** It must be valid throughout whole lifetime of created allocator. */
  597. VkPhysicalDevice physicalDevice;
  598. /// Vulkan device.
  599. /** It must be valid throughout whole lifetime of created allocator. */
  600. VkDevice device;
  601. /// Preferred size of a single `VkDeviceMemory` block to be allocated from large heaps.
  602. /** Set to 0 to use default, which is currently 256 MB. */
  603. VkDeviceSize preferredLargeHeapBlockSize;
  604. /// Preferred size of a single `VkDeviceMemory` block to be allocated from small heaps <= 512 MB.
  605. /** Set to 0 to use default, which is currently 64 MB. */
  606. VkDeviceSize preferredSmallHeapBlockSize;
  607. /// Custom CPU memory allocation callbacks.
  608. /** Optional, can be null. When specified, will also be used for all CPU-side memory allocations. */
  609. const VkAllocationCallbacks* pAllocationCallbacks;
  610. /// Informative callbacks for vkAllocateMemory, vkFreeMemory.
  611. /** Optional, can be null. */
  612. const VmaDeviceMemoryCallbacks* pDeviceMemoryCallbacks;
  613. /** \brief Maximum number of additional frames that are in use at the same time as current frame.
  614. This value is used only when you make allocations with
  615. VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT flag. Such allocation cannot become
  616. lost if allocation.lastUseFrameIndex >= allocator.currentFrameIndex - frameInUseCount.
  617. For example, if you double-buffer your command buffers, so resources used for
  618. rendering in previous frame may still be in use by the GPU at the moment you
  619. allocate resources needed for the current frame, set this value to 1.
  620. If you want to allow any allocations other than used in the current frame to
  621. become lost, set this value to 0.
  622. */
  623. uint32_t frameInUseCount;
  624. /** \brief Either NULL or a pointer to an array of limits on maximum number of bytes that can be allocated out of particular Vulkan memory heap.
  625. If not NULL, it must be a pointer to an array of
  626. `VkPhysicalDeviceMemoryProperties::memoryHeapCount` elements, defining limit on
  627. maximum number of bytes that can be allocated out of particular Vulkan memory
  628. heap.
  629. Any of the elements may be equal to `VK_WHOLE_SIZE`, which means no limit on that
  630. heap. This is also the default in case of `pHeapSizeLimit` = NULL.
  631. If there is a limit defined for a heap:
  632. - If user tries to allocate more memory from that heap using this allocator,
  633. the allocation fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY`.
  634. - If the limit is smaller than heap size reported in `VkMemoryHeap::size`, the
  635. value of this limit will be reported instead when using vmaGetMemoryProperties().
  636. Warning! Using this feature may not be equivalent to installing a GPU with
  637. smaller amount of memory, because graphics driver doesn't necessary fail new
  638. allocations with `VK_ERROR_OUT_OF_DEVICE_MEMORY` result when memory capacity is
  639. exceeded. It may return success and just silently migrate some device memory
  640. blocks to system RAM.
  641. */
  642. const VkDeviceSize* pHeapSizeLimit;
  643. /** \brief Pointers to Vulkan functions. Can be null if you leave define `VMA_STATIC_VULKAN_FUNCTIONS 1`.
  644. If you leave define `VMA_STATIC_VULKAN_FUNCTIONS 1` in configuration section,
  645. you can pass null as this member, because the library will fetch pointers to
  646. Vulkan functions internally in a static way, like:
  647. vulkanFunctions.vkAllocateMemory = &vkAllocateMemory;
  648. Fill this member if you want to provide your own pointers to Vulkan functions,
  649. e.g. fetched using `vkGetInstanceProcAddr()` and `vkGetDeviceProcAddr()`.
  650. */
  651. const VmaVulkanFunctions* pVulkanFunctions;
  652. } VmaAllocatorCreateInfo;
  653. /// Creates Allocator object.
  654. VkResult vmaCreateAllocator(
  655. const VmaAllocatorCreateInfo* pCreateInfo,
  656. VmaAllocator* pAllocator);
  657. /// Destroys allocator object.
  658. void vmaDestroyAllocator(
  659. VmaAllocator allocator);
  660. /**
  661. PhysicalDeviceProperties are fetched from physicalDevice by the allocator.
  662. You can access it here, without fetching it again on your own.
  663. */
  664. void vmaGetPhysicalDeviceProperties(
  665. VmaAllocator allocator,
  666. const VkPhysicalDeviceProperties** ppPhysicalDeviceProperties);
  667. /**
  668. PhysicalDeviceMemoryProperties are fetched from physicalDevice by the allocator.
  669. You can access it here, without fetching it again on your own.
  670. */
  671. void vmaGetMemoryProperties(
  672. VmaAllocator allocator,
  673. const VkPhysicalDeviceMemoryProperties** ppPhysicalDeviceMemoryProperties);
  674. /**
  675. \brief Given Memory Type Index, returns Property Flags of this memory type.
  676. This is just a convenience function. Same information can be obtained using
  677. vmaGetMemoryProperties().
  678. */
  679. void vmaGetMemoryTypeProperties(
  680. VmaAllocator allocator,
  681. uint32_t memoryTypeIndex,
  682. VkMemoryPropertyFlags* pFlags);
  683. /** \brief Sets index of the current frame.
  684. This function must be used if you make allocations with
  685. `VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT` and
  686. `VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT` flags to inform the allocator
  687. when a new frame begins. Allocations queried using vmaGetAllocationInfo() cannot
  688. become lost in the current frame.
  689. */
  690. void vmaSetCurrentFrameIndex(
  691. VmaAllocator allocator,
  692. uint32_t frameIndex);
  693. /** \brief Calculated statistics of memory usage in entire allocator.
  694. */
  695. typedef struct VmaStatInfo
  696. {
  697. /// Number of `VkDeviceMemory` Vulkan memory blocks allocated.
  698. uint32_t blockCount;
  699. /// Number of `VmaAllocation` allocation objects allocated.
  700. uint32_t allocationCount;
  701. /// Number of free ranges of memory between allocations.
  702. uint32_t unusedRangeCount;
  703. /// Total number of bytes occupied by all allocations.
  704. VkDeviceSize usedBytes;
  705. /// Total number of bytes occupied by unused ranges.
  706. VkDeviceSize unusedBytes;
  707. VkDeviceSize allocationSizeMin, allocationSizeAvg, allocationSizeMax;
  708. VkDeviceSize unusedRangeSizeMin, unusedRangeSizeAvg, unusedRangeSizeMax;
  709. } VmaStatInfo;
  710. /// General statistics from current state of Allocator.
  711. typedef struct VmaStats
  712. {
  713. VmaStatInfo memoryType[VK_MAX_MEMORY_TYPES];
  714. VmaStatInfo memoryHeap[VK_MAX_MEMORY_HEAPS];
  715. VmaStatInfo total;
  716. } VmaStats;
  717. /// Retrieves statistics from current state of the Allocator.
  718. void vmaCalculateStats(
  719. VmaAllocator allocator,
  720. VmaStats* pStats);
  721. #define VMA_STATS_STRING_ENABLED 1
  722. #if VMA_STATS_STRING_ENABLED
  723. /// Builds and returns statistics as string in JSON format.
  724. /** @param[out] ppStatsString Must be freed using vmaFreeStatsString() function.
  725. */
  726. void vmaBuildStatsString(
  727. VmaAllocator allocator,
  728. char** ppStatsString,
  729. VkBool32 detailedMap);
  730. void vmaFreeStatsString(
  731. VmaAllocator allocator,
  732. char* pStatsString);
  733. #endif // #if VMA_STATS_STRING_ENABLED
  734. VK_DEFINE_HANDLE(VmaPool)
  735. typedef enum VmaMemoryUsage
  736. {
  737. /** No intended memory usage specified.
  738. Use other members of VmaAllocationCreateInfo to specify your requirements.
  739. */
  740. VMA_MEMORY_USAGE_UNKNOWN = 0,
  741. /** Memory will be used on device only, so faster access from the device is preferred.
  742. It usually means device-local GPU memory.
  743. No need to be mappable on host.
  744. Good e.g. for images to be used as attachments, images containing textures to be sampled,
  745. buffers used as vertex buffer, index buffer, uniform buffer and majority of
  746. other types of resources used by device.
  747. You can still do transfers from/to such resource to/from host memory.
  748. The allocation may still end up in `HOST_VISIBLE` memory on some implementations.
  749. In such case, you are free to map it.
  750. You can also use `VMA_ALLOCATION_CREATE_MAPPED_BIT` with this usage type.
  751. */
  752. VMA_MEMORY_USAGE_GPU_ONLY = 1,
  753. /** Memory will be mapped and used on host.
  754. It usually means CPU system memory.
  755. Could be used for transfer to/from device.
  756. Good e.g. for "staging" copy of buffers and images, used as transfer source or destination.
  757. Resources created in this pool may still be accessible to the device, but access to them can be slower.
  758. Guarantees to be `HOST_VISIBLE` and `HOST_COHERENT`.
  759. */
  760. VMA_MEMORY_USAGE_CPU_ONLY = 2,
  761. /** Memory will be used for frequent (dynamic) updates from host and reads on device (upload).
  762. Good e.g. for vertex buffers or uniform buffers updated every frame.
  763. Guarantees to be `HOST_VISIBLE`.
  764. */
  765. VMA_MEMORY_USAGE_CPU_TO_GPU = 3,
  766. /** Memory will be used for frequent writing on device and readback on host (download).
  767. Guarantees to be `HOST_VISIBLE`.
  768. */
  769. VMA_MEMORY_USAGE_GPU_TO_CPU = 4,
  770. VMA_MEMORY_USAGE_MAX_ENUM = 0x7FFFFFFF
  771. } VmaMemoryUsage;
  772. /// Flags to be passed as VmaAllocationCreateInfo::flags.
  773. typedef enum VmaAllocationCreateFlagBits {
  774. /** \brief Set this flag if the allocation should have its own memory block.
  775. Use it for special, big resources, like fullscreen images used as attachments.
  776. This flag must also be used for host visible resources that you want to map
  777. simultaneously because otherwise they might end up as regions of the same
  778. `VkDeviceMemory`, while mapping same `VkDeviceMemory` multiple times
  779. simultaneously is illegal.
  780. You should not use this flag if VmaAllocationCreateInfo::pool is not null.
  781. */
  782. VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT = 0x00000001,
  783. /** \brief Set this flag to only try to allocate from existing `VkDeviceMemory` blocks and never create new such block.
  784. If new allocation cannot be placed in any of the existing blocks, allocation
  785. fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY` error.
  786. You should not use `VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT` and
  787. `VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT` at the same time. It makes no sense.
  788. If VmaAllocationCreateInfo::pool is not null, this flag is implied and ignored. */
  789. VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT = 0x00000002,
  790. /** \brief Set this flag to use a memory that will be persistently mapped and retrieve pointer to it.
  791. Pointer to mapped memory will be returned through VmaAllocationInfo::pMappedData.
  792. Is it valid to use this flag for allocation made from memory type that is not
  793. `HOST_VISIBLE`. This flag is then ignored and memory is not mapped. This is
  794. useful if you need an allocation that is efficient to use on GPU
  795. (`DEVICE_LOCAL`) and still want to map it directly if possible on platforms that
  796. support it (e.g. Intel GPU).
  797. You should not use this flag together with `VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT`.
  798. */
  799. VMA_ALLOCATION_CREATE_MAPPED_BIT = 0x00000004,
  800. /** Allocation created with this flag can become lost as a result of another
  801. allocation with `VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT` flag, so you
  802. must check it before use.
  803. To check if allocation is not lost, call vmaGetAllocationInfo() and check if
  804. VmaAllocationInfo::deviceMemory is not `VK_NULL_HANDLE`.
  805. For details about supporting lost allocations, see Lost Allocations
  806. chapter of User Guide on Main Page.
  807. You should not use this flag together with `VMA_ALLOCATION_CREATE_MAPPED_BIT`.
  808. */
  809. VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT = 0x00000008,
  810. /** While creating allocation using this flag, other allocations that were
  811. created with flag `VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT` can become lost.
  812. For details about supporting lost allocations, see Lost Allocations
  813. chapter of User Guide on Main Page.
  814. */
  815. VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT = 0x00000010,
  816. /** Set this flag to treat VmaAllocationCreateInfo::pUserData as pointer to a
  817. null-terminated string. Instead of copying pointer value, a local copy of the
  818. string is made and stored in allocation's pUserData. The string is automatically
  819. freed together with the allocation. It is also used in vmaBuildStatsString().
  820. */
  821. VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT = 0x00000020,
  822. VMA_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
  823. } VmaAllocationCreateFlagBits;
  824. typedef VkFlags VmaAllocationCreateFlags;
  825. typedef struct VmaAllocationCreateInfo
  826. {
  827. /// Use VmaAllocationCreateFlagBits enum.
  828. VmaAllocationCreateFlags flags;
  829. /** \brief Intended usage of memory.
  830. You can leave `VMA_MEMORY_USAGE_UNKNOWN` if you specify memory requirements in other way. \n
  831. If `pool` is not null, this member is ignored.
  832. */
  833. VmaMemoryUsage usage;
  834. /** \brief Flags that must be set in a Memory Type chosen for an allocation.
  835. Leave 0 if you specify memory requirements in other way. \n
  836. If `pool` is not null, this member is ignored.*/
  837. VkMemoryPropertyFlags requiredFlags;
  838. /** \brief Flags that preferably should be set in a memory type chosen for an allocation.
  839. Set to 0 if no additional flags are prefered. \n
  840. If `pool` is not null, this member is ignored. */
  841. VkMemoryPropertyFlags preferredFlags;
  842. /** \brief Bitmask containing one bit set for every memory type acceptable for this allocation.
  843. Value 0 is equivalent to `UINT32_MAX` - it means any memory type is accepted if
  844. it meets other requirements specified by this structure, with no further
  845. restrictions on memory type index. \n
  846. If `pool` is not null, this member is ignored.
  847. */
  848. uint32_t memoryTypeBits;
  849. /** \brief Pool that this allocation should be created in.
  850. Leave `VK_NULL_HANDLE` to allocate from default pool. If not null, members:
  851. `usage`, `requiredFlags`, `preferredFlags`, `memoryTypeBits` are ignored.
  852. */
  853. VmaPool pool;
  854. /** \brief Custom general-purpose pointer that will be stored in VmaAllocation, can be read as VmaAllocationInfo::pUserData and changed using vmaSetAllocationUserData().
  855. If `VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT` is used, it must be either
  856. null or pointer to a null-terminated string. The string will be then copied to
  857. internal buffer, so it doesn't need to be valid after allocation call.
  858. */
  859. void* pUserData;
  860. } VmaAllocationCreateInfo;
  861. /**
  862. This algorithm tries to find a memory type that:
  863. - Is allowed by memoryTypeBits.
  864. - Contains all the flags from pAllocationCreateInfo->requiredFlags.
  865. - Matches intended usage.
  866. - Has as many flags from pAllocationCreateInfo->preferredFlags as possible.
  867. \return Returns VK_ERROR_FEATURE_NOT_PRESENT if not found. Receiving such result
  868. from this function or any other allocating function probably means that your
  869. device doesn't support any memory type with requested features for the specific
  870. type of resource you want to use it for. Please check parameters of your
  871. resource, like image layout (OPTIMAL versus LINEAR) or mip level count.
  872. */
  873. VkResult vmaFindMemoryTypeIndex(
  874. VmaAllocator allocator,
  875. uint32_t memoryTypeBits,
  876. const VmaAllocationCreateInfo* pAllocationCreateInfo,
  877. uint32_t* pMemoryTypeIndex);
  878. /// Flags to be passed as VmaPoolCreateInfo::flags.
  879. typedef enum VmaPoolCreateFlagBits {
  880. /** \brief Use this flag if you always allocate only buffers and linear images or only optimal images out of this pool and so Buffer-Image Granularity can be ignored.
  881. This is na optional optimization flag.
  882. If you always allocate using vmaCreateBuffer(), vmaCreateImage(),
  883. vmaAllocateMemoryForBuffer(), then you don't need to use it because allocator
  884. knows exact type of your allocations so it can handle Buffer-Image Granularity
  885. in the optimal way.
  886. If you also allocate using vmaAllocateMemoryForImage() or vmaAllocateMemory(),
  887. exact type of such allocations is not known, so allocator must be conservative
  888. in handling Buffer-Image Granularity, which can lead to suboptimal allocation
  889. (wasted memory). In that case, if you can make sure you always allocate only
  890. buffers and linear images or only optimal images out of this pool, use this flag
  891. to make allocator disregard Buffer-Image Granularity and so make allocations
  892. more optimal.
  893. */
  894. VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT = 0x00000002,
  895. VMA_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
  896. } VmaPoolCreateFlagBits;
  897. typedef VkFlags VmaPoolCreateFlags;
  898. /** \brief Describes parameter of created `VmaPool`.
  899. */
  900. typedef struct VmaPoolCreateInfo {
  901. /** \brief Vulkan memory type index to allocate this pool from.
  902. */
  903. uint32_t memoryTypeIndex;
  904. /** \brief Use combination of `VmaPoolCreateFlagBits`.
  905. */
  906. VmaPoolCreateFlags flags;
  907. /** \brief Size of a single `VkDeviceMemory` block to be allocated as part of this pool, in bytes.
  908. Optional. Leave 0 to use default.
  909. */
  910. VkDeviceSize blockSize;
  911. /** \brief Minimum number of blocks to be always allocated in this pool, even if they stay empty.
  912. Set to 0 to have no preallocated blocks and let the pool be completely empty.
  913. */
  914. size_t minBlockCount;
  915. /** \brief Maximum number of blocks that can be allocated in this pool.
  916. Optional. Set to 0 to use `SIZE_MAX`, which means no limit.
  917. Set to same value as minBlockCount to have fixed amount of memory allocated
  918. throuout whole lifetime of this pool.
  919. */
  920. size_t maxBlockCount;
  921. /** \brief Maximum number of additional frames that are in use at the same time as current frame.
  922. This value is used only when you make allocations with
  923. `VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT` flag. Such allocation cannot become
  924. lost if allocation.lastUseFrameIndex >= allocator.currentFrameIndex - frameInUseCount.
  925. For example, if you double-buffer your command buffers, so resources used for
  926. rendering in previous frame may still be in use by the GPU at the moment you
  927. allocate resources needed for the current frame, set this value to 1.
  928. If you want to allow any allocations other than used in the current frame to
  929. become lost, set this value to 0.
  930. */
  931. uint32_t frameInUseCount;
  932. } VmaPoolCreateInfo;
  933. /** \brief Describes parameter of existing `VmaPool`.
  934. */
  935. typedef struct VmaPoolStats {
  936. /** \brief Total amount of `VkDeviceMemory` allocated from Vulkan for this pool, in bytes.
  937. */
  938. VkDeviceSize size;
  939. /** \brief Total number of bytes in the pool not used by any `VmaAllocation`.
  940. */
  941. VkDeviceSize unusedSize;
  942. /** \brief Number of VmaAllocation objects created from this pool that were not destroyed or lost.
  943. */
  944. size_t allocationCount;
  945. /** \brief Number of continuous memory ranges in the pool not used by any `VmaAllocation`.
  946. */
  947. size_t unusedRangeCount;
  948. /** \brief Size of the largest continuous free memory region.
  949. Making a new allocation of that size is not guaranteed to succeed because of
  950. possible additional margin required to respect alignment and buffer/image
  951. granularity.
  952. */
  953. VkDeviceSize unusedRangeSizeMax;
  954. } VmaPoolStats;
  955. /** \brief Allocates Vulkan device memory and creates `VmaPool` object.
  956. @param allocator Allocator object.
  957. @param pCreateInfo Parameters of pool to create.
  958. @param[out] pPool Handle to created pool.
  959. */
  960. VkResult vmaCreatePool(
  961. VmaAllocator allocator,
  962. const VmaPoolCreateInfo* pCreateInfo,
  963. VmaPool* pPool);
  964. /** \brief Destroys VmaPool object and frees Vulkan device memory.
  965. */
  966. void vmaDestroyPool(
  967. VmaAllocator allocator,
  968. VmaPool pool);
  969. /** \brief Retrieves statistics of existing VmaPool object.
  970. @param allocator Allocator object.
  971. @param pool Pool object.
  972. @param[out] pPoolStats Statistics of specified pool.
  973. */
  974. void vmaGetPoolStats(
  975. VmaAllocator allocator,
  976. VmaPool pool,
  977. VmaPoolStats* pPoolStats);
  978. /** \brief Marks all allocations in given pool as lost if they are not used in current frame or VmaPoolCreateInfo::frameInUseCount back from now.
  979. @param allocator Allocator object.
  980. @param pool Pool.
  981. @param[out] pLostAllocationCount Number of allocations marked as lost. Optional - pass null if you don't need this information.
  982. */
  983. void vmaMakePoolAllocationsLost(
  984. VmaAllocator allocator,
  985. VmaPool pool,
  986. size_t* pLostAllocationCount);
  987. VK_DEFINE_HANDLE(VmaAllocation)
  988. /** \brief Parameters of `VmaAllocation` objects, that can be retrieved using function vmaGetAllocationInfo().
  989. */
  990. typedef struct VmaAllocationInfo {
  991. /** \brief Memory type index that this allocation was allocated from.
  992. It never changes.
  993. */
  994. uint32_t memoryType;
  995. /** \brief Handle to Vulkan memory object.
  996. Same memory object can be shared by multiple allocations.
  997. It can change after call to vmaDefragment() if this allocation is passed to the function, or if allocation is lost.
  998. If the allocation is lost, it is equal to `VK_NULL_HANDLE`.
  999. */
  1000. VkDeviceMemory deviceMemory;
  1001. /** \brief Offset into deviceMemory object to the beginning of this allocation, in bytes. (deviceMemory, offset) pair is unique to this allocation.
  1002. It can change after call to vmaDefragment() if this allocation is passed to the function, or if allocation is lost.
  1003. */
  1004. VkDeviceSize offset;
  1005. /** \brief Size of this allocation, in bytes.
  1006. It never changes, unless allocation is lost.
  1007. */
  1008. VkDeviceSize size;
  1009. /** \brief Pointer to the beginning of this allocation as mapped data.
  1010. If the allocation hasn't been mapped using vmaMapMemory() and hasn't been
  1011. created with `VMA_ALLOCATION_CREATE_MAPPED_BIT` flag, this value null.
  1012. It can change after call to vmaMapMemory(), vmaUnmapMemory().
  1013. It can also change after call to vmaDefragment() if this allocation is passed to the function.
  1014. */
  1015. void* pMappedData;
  1016. /** \brief Custom general-purpose pointer that was passed as VmaAllocationCreateInfo::pUserData or set using vmaSetAllocationUserData().
  1017. It can change after call to vmaSetAllocationUserData() for this allocation.
  1018. */
  1019. void* pUserData;
  1020. } VmaAllocationInfo;
  1021. /** \brief General purpose memory allocation.
  1022. @param[out] pAllocation Handle to allocated memory.
  1023. @param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo().
  1024. You should free the memory using vmaFreeMemory().
  1025. It is recommended to use vmaAllocateMemoryForBuffer(), vmaAllocateMemoryForImage(),
  1026. vmaCreateBuffer(), vmaCreateImage() instead whenever possible.
  1027. */
  1028. VkResult vmaAllocateMemory(
  1029. VmaAllocator allocator,
  1030. const VkMemoryRequirements* pVkMemoryRequirements,
  1031. const VmaAllocationCreateInfo* pCreateInfo,
  1032. VmaAllocation* pAllocation,
  1033. VmaAllocationInfo* pAllocationInfo);
  1034. /**
  1035. @param[out] pAllocation Handle to allocated memory.
  1036. @param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo().
  1037. You should free the memory using vmaFreeMemory().
  1038. */
  1039. VkResult vmaAllocateMemoryForBuffer(
  1040. VmaAllocator allocator,
  1041. VkBuffer buffer,
  1042. const VmaAllocationCreateInfo* pCreateInfo,
  1043. VmaAllocation* pAllocation,
  1044. VmaAllocationInfo* pAllocationInfo);
  1045. /// Function similar to vmaAllocateMemoryForBuffer().
  1046. VkResult vmaAllocateMemoryForImage(
  1047. VmaAllocator allocator,
  1048. VkImage image,
  1049. const VmaAllocationCreateInfo* pCreateInfo,
  1050. VmaAllocation* pAllocation,
  1051. VmaAllocationInfo* pAllocationInfo);
  1052. /// Frees memory previously allocated using vmaAllocateMemory(), vmaAllocateMemoryForBuffer(), or vmaAllocateMemoryForImage().
  1053. void vmaFreeMemory(
  1054. VmaAllocator allocator,
  1055. VmaAllocation allocation);
  1056. /// Returns current information about specified allocation.
  1057. void vmaGetAllocationInfo(
  1058. VmaAllocator allocator,
  1059. VmaAllocation allocation,
  1060. VmaAllocationInfo* pAllocationInfo);
  1061. /** \brief Sets pUserData in given allocation to new value.
  1062. If the allocation was created with VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT,
  1063. pUserData must be either null, or pointer to a null-terminated string. The function
  1064. makes local copy of the string and sets it as allocation's pUserData. String
  1065. passed as pUserData doesn't need to be valid for whole lifetime of the allocation -
  1066. you can free it after this call. String previously pointed by allocation's
  1067. pUserData is freed from memory.
  1068. If the flag was not used, the value of pointer pUserData is just copied to
  1069. allocation's pUserData. It is opaque, so you can use it however you want - e.g.
  1070. as a pointer, ordinal number or some handle to you own data.
  1071. */
  1072. void vmaSetAllocationUserData(
  1073. VmaAllocator allocator,
  1074. VmaAllocation allocation,
  1075. void* pUserData);
  1076. /** \brief Creates new allocation that is in lost state from the beginning.
  1077. It can be useful if you need a dummy, non-null allocation.
  1078. You still need to destroy created object using vmaFreeMemory().
  1079. Returned allocation is not tied to any specific memory pool or memory type and
  1080. not bound to any image or buffer. It has size = 0. It cannot be turned into
  1081. a real, non-empty allocation.
  1082. */
  1083. void vmaCreateLostAllocation(
  1084. VmaAllocator allocator,
  1085. VmaAllocation* pAllocation);
  1086. /** \brief Maps memory represented by given allocation and returns pointer to it.
  1087. Maps memory represented by given allocation to make it accessible to CPU code.
  1088. When succeeded, `*ppData` contains pointer to first byte of this memory.
  1089. If the allocation is part of bigger `VkDeviceMemory` block, the pointer is
  1090. correctly offseted to the beginning of region assigned to this particular
  1091. allocation.
  1092. Mapping is internally reference-counted and synchronized, so despite raw Vulkan
  1093. function `vkMapMemory()` cannot be used to map same block of `VkDeviceMemory`
  1094. multiple times simultaneously, it is safe to call this function on allocations
  1095. assigned to the same memory block. Actual Vulkan memory will be mapped on first
  1096. mapping and unmapped on last unmapping.
  1097. If the function succeeded, you must call vmaUnmapMemory() to unmap the
  1098. allocation when mapping is no longer needed or before freeing the allocation, at
  1099. the latest.
  1100. It also safe to call this function multiple times on the same allocation. You
  1101. must call vmaUnmapMemory() same number of times as you called vmaMapMemory().
  1102. It is also safe to call this function on allocation created with
  1103. `VMA_ALLOCATION_CREATE_MAPPED_BIT` flag. Its memory stays mapped all the time.
  1104. You must still call vmaUnmapMemory() same number of times as you called
  1105. vmaMapMemory(). You must not call vmaUnmapMemory() additional time to free the
  1106. "0-th" mapping made automatically due to `VMA_ALLOCATION_CREATE_MAPPED_BIT` flag.
  1107. This function fails when used on allocation made in memory type that is not
  1108. `HOST_VISIBLE`.
  1109. This function always fails when called for allocation that was created with
  1110. `VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT` flag. Such allocations cannot be
  1111. mapped.
  1112. */
  1113. VkResult vmaMapMemory(
  1114. VmaAllocator allocator,
  1115. VmaAllocation allocation,
  1116. void** ppData);
  1117. /** \brief Unmaps memory represented by given allocation, mapped previously using vmaMapMemory().
  1118. For details, see description of vmaMapMemory().
  1119. */
  1120. void vmaUnmapMemory(
  1121. VmaAllocator allocator,
  1122. VmaAllocation allocation);
  1123. /** \brief Optional configuration parameters to be passed to function vmaDefragment(). */
  1124. typedef struct VmaDefragmentationInfo {
  1125. /** \brief Maximum total numbers of bytes that can be copied while moving allocations to different places.
  1126. Default is `VK_WHOLE_SIZE`, which means no limit.
  1127. */
  1128. VkDeviceSize maxBytesToMove;
  1129. /** \brief Maximum number of allocations that can be moved to different place.
  1130. Default is `UINT32_MAX`, which means no limit.
  1131. */
  1132. uint32_t maxAllocationsToMove;
  1133. } VmaDefragmentationInfo;
  1134. /** \brief Statistics returned by function vmaDefragment(). */
  1135. typedef struct VmaDefragmentationStats {
  1136. /// Total number of bytes that have been copied while moving allocations to different places.
  1137. VkDeviceSize bytesMoved;
  1138. /// Total number of bytes that have been released to the system by freeing empty `VkDeviceMemory` objects.
  1139. VkDeviceSize bytesFreed;
  1140. /// Number of allocations that have been moved to different places.
  1141. uint32_t allocationsMoved;
  1142. /// Number of empty `VkDeviceMemory` objects that have been released to the system.
  1143. uint32_t deviceMemoryBlocksFreed;
  1144. } VmaDefragmentationStats;
  1145. /** \brief Compacts memory by moving allocations.
  1146. @param pAllocations Array of allocations that can be moved during this compation.
  1147. @param allocationCount Number of elements in pAllocations and pAllocationsChanged arrays.
  1148. @param[out] pAllocationsChanged Array of boolean values that will indicate whether matching allocation in pAllocations array has been moved. This parameter is optional. Pass null if you don't need this information.
  1149. @param pDefragmentationInfo Configuration parameters. Optional - pass null to use default values.
  1150. @param[out] pDefragmentationStats Statistics returned by the function. Optional - pass null if you don't need this information.
  1151. @return VK_SUCCESS if completed, VK_INCOMPLETE if succeeded but didn't make all possible optimizations because limits specified in pDefragmentationInfo have been reached, negative error code in case of error.
  1152. This function works by moving allocations to different places (different
  1153. `VkDeviceMemory` objects and/or different offsets) in order to optimize memory
  1154. usage. Only allocations that are in pAllocations array can be moved. All other
  1155. allocations are considered nonmovable in this call. Basic rules:
  1156. - Only allocations made in memory types that have
  1157. `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` flag can be compacted. You may pass other
  1158. allocations but it makes no sense - these will never be moved.
  1159. - You may pass allocations made with `VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT` but
  1160. it makes no sense - they will never be moved.
  1161. - Both allocations made with or without `VMA_ALLOCATION_CREATE_MAPPED_BIT`
  1162. flag can be compacted. If not persistently mapped, memory will be mapped
  1163. temporarily inside this function if needed.
  1164. - You must not pass same `VmaAllocation` object multiple times in pAllocations array.
  1165. The function also frees empty `VkDeviceMemory` blocks.
  1166. After allocation has been moved, its VmaAllocationInfo::deviceMemory and/or
  1167. VmaAllocationInfo::offset changes. You must query them again using
  1168. vmaGetAllocationInfo() if you need them.
  1169. If an allocation has been moved, data in memory is copied to new place
  1170. automatically, but if it was bound to a buffer or an image, you must destroy
  1171. that object yourself, create new one and bind it to the new memory pointed by
  1172. the allocation. You must use `vkDestroyBuffer()`, `vkDestroyImage()`,
  1173. `vkCreateBuffer()`, `vkCreateImage()` for that purpose and NOT vmaDestroyBuffer(),
  1174. vmaDestroyImage(), vmaCreateBuffer(), vmaCreateImage()! Example:
  1175. \code
  1176. VkDevice device = ...;
  1177. VmaAllocator allocator = ...;
  1178. std::vector<VkBuffer> buffers = ...;
  1179. std::vector<VmaAllocation> allocations = ...;
  1180. std::vector<VkBool32> allocationsChanged(allocations.size());
  1181. vmaDefragment(allocator, allocations.data(), allocations.size(), allocationsChanged.data(), nullptr, nullptr);
  1182. for(size_t i = 0; i < allocations.size(); ++i)
  1183. {
  1184. if(allocationsChanged[i])
  1185. {
  1186. VmaAllocationInfo allocInfo;
  1187. vmaGetAllocationInfo(allocator, allocations[i], &allocInfo);
  1188. vkDestroyBuffer(device, buffers[i], nullptr);
  1189. VkBufferCreateInfo bufferInfo = ...;
  1190. vkCreateBuffer(device, &bufferInfo, nullptr, &buffers[i]);
  1191. // You can make dummy call to vkGetBufferMemoryRequirements here to silence validation layer warning.
  1192. vkBindBufferMemory(device, buffers[i], allocInfo.deviceMemory, allocInfo.offset);
  1193. }
  1194. }
  1195. \endcode
  1196. Warning! This function is not correct according to Vulkan specification. Use it
  1197. at your own risk. That's becuase Vulkan doesn't guarantee that memory
  1198. requirements (size and alignment) for a new buffer or image are consistent. They
  1199. may be different even for subsequent calls with the same parameters. It really
  1200. does happen on some platforms, especially with images.
  1201. This function may be time-consuming, so you shouldn't call it too often (like
  1202. every frame or after every resource creation/destruction), but rater you can
  1203. call it on special occasions (like when reloading a game level, when you just
  1204. destroyed a lot of objects).
  1205. */
  1206. VkResult vmaDefragment(
  1207. VmaAllocator allocator,
  1208. VmaAllocation* pAllocations,
  1209. size_t allocationCount,
  1210. VkBool32* pAllocationsChanged,
  1211. const VmaDefragmentationInfo *pDefragmentationInfo,
  1212. VmaDefragmentationStats* pDefragmentationStats);
  1213. /**
  1214. @param[out] pBuffer Buffer that was created.
  1215. @param[out] pAllocation Allocation that was created.
  1216. @param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo().
  1217. This function automatically:
  1218. -# Creates buffer.
  1219. -# Allocates appropriate memory for it.
  1220. -# Binds the buffer with the memory.
  1221. If any of these operations fail, buffer and allocation are not created,
  1222. returned value is negative error code, *pBuffer and *pAllocation are null.
  1223. If the function succeeded, you must destroy both buffer and allocation when you
  1224. no longer need them using either convenience function vmaDestroyBuffer() or
  1225. separately, using `vkDestroyBuffer()` and vmaFreeMemory().
  1226. If VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT flag was used,
  1227. VK_KHR_dedicated_allocation extension is used internally to query driver whether
  1228. it requires or prefers the new buffer to have dedicated allocation. If yes,
  1229. and if dedicated allocation is possible (VmaAllocationCreateInfo::pool is null
  1230. and VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT is not used), it creates dedicated
  1231. allocation for this buffer, just like when using
  1232. VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT.
  1233. */
  1234. VkResult vmaCreateBuffer(
  1235. VmaAllocator allocator,
  1236. const VkBufferCreateInfo* pBufferCreateInfo,
  1237. const VmaAllocationCreateInfo* pAllocationCreateInfo,
  1238. VkBuffer* pBuffer,
  1239. VmaAllocation* pAllocation,
  1240. VmaAllocationInfo* pAllocationInfo);
  1241. /** \brief Destroys Vulkan buffer and frees allocated memory.
  1242. This is just a convenience function equivalent to:
  1243. \code
  1244. vkDestroyBuffer(device, buffer, allocationCallbacks);
  1245. vmaFreeMemory(allocator, allocation);
  1246. \endcode
  1247. It it safe to pass null as buffer and/or allocation.
  1248. */
  1249. void vmaDestroyBuffer(
  1250. VmaAllocator allocator,
  1251. VkBuffer buffer,
  1252. VmaAllocation allocation);
  1253. /// Function similar to vmaCreateBuffer().
  1254. VkResult vmaCreateImage(
  1255. VmaAllocator allocator,
  1256. const VkImageCreateInfo* pImageCreateInfo,
  1257. const VmaAllocationCreateInfo* pAllocationCreateInfo,
  1258. VkImage* pImage,
  1259. VmaAllocation* pAllocation,
  1260. VmaAllocationInfo* pAllocationInfo);
  1261. /** \brief Destroys Vulkan image and frees allocated memory.
  1262. This is just a convenience function equivalent to:
  1263. \code
  1264. vkDestroyImage(device, image, allocationCallbacks);
  1265. vmaFreeMemory(allocator, allocation);
  1266. \endcode
  1267. It it safe to pass null as image and/or allocation.
  1268. */
  1269. void vmaDestroyImage(
  1270. VmaAllocator allocator,
  1271. VkImage image,
  1272. VmaAllocation allocation);
  1273. #ifdef __cplusplus
  1274. }
  1275. #endif
  1276. #endif // AMD_VULKAN_MEMORY_ALLOCATOR_H
  1277. // For Visual Studio IntelliSense.
  1278. #ifdef __INTELLISENSE__
  1279. #define VMA_IMPLEMENTATION
  1280. #endif
  1281. #ifdef VMA_IMPLEMENTATION
  1282. #undef VMA_IMPLEMENTATION
  1283. #include <cstdint>
  1284. #include <cstdlib>
  1285. #include <cstring>
  1286. /*******************************************************************************
  1287. CONFIGURATION SECTION
  1288. Define some of these macros before each #include of this header or change them
  1289. here if you need other then default behavior depending on your environment.
  1290. */
  1291. /*
  1292. Define this macro to 1 to make the library fetch pointers to Vulkan functions
  1293. internally, like:
  1294. vulkanFunctions.vkAllocateMemory = &vkAllocateMemory;
  1295. Define to 0 if you are going to provide you own pointers to Vulkan functions via
  1296. VmaAllocatorCreateInfo::pVulkanFunctions.
  1297. */
  1298. #ifndef VMA_STATIC_VULKAN_FUNCTIONS
  1299. #define VMA_STATIC_VULKAN_FUNCTIONS 1
  1300. #endif
  1301. // Define this macro to 1 to make the library use STL containers instead of its own implementation.
  1302. //#define VMA_USE_STL_CONTAINERS 1
  1303. /* Set this macro to 1 to make the library including and using STL containers:
  1304. std::pair, std::vector, std::list, std::unordered_map.
  1305. Set it to 0 or undefined to make the library using its own implementation of
  1306. the containers.
  1307. */
  1308. #if VMA_USE_STL_CONTAINERS
  1309. #define VMA_USE_STL_VECTOR 1
  1310. #define VMA_USE_STL_UNORDERED_MAP 1
  1311. #define VMA_USE_STL_LIST 1
  1312. #endif
  1313. #if VMA_USE_STL_VECTOR
  1314. #include <vector>
  1315. #endif
  1316. #if VMA_USE_STL_UNORDERED_MAP
  1317. #include <unordered_map>
  1318. #endif
  1319. #if VMA_USE_STL_LIST
  1320. #include <list>
  1321. #endif
  1322. /*
  1323. Following headers are used in this CONFIGURATION section only, so feel free to
  1324. remove them if not needed.
  1325. */
  1326. #include <cassert> // for assert
  1327. #include <algorithm> // for min, max
  1328. #include <mutex> // for std::mutex
  1329. #include <atomic> // for std::atomic
  1330. #if !defined(_WIN32)
  1331. #include <malloc.h> // for aligned_alloc()
  1332. #endif
  1333. // Normal assert to check for programmer's errors, especially in Debug configuration.
  1334. #ifndef VMA_ASSERT
  1335. #ifdef _DEBUG
  1336. #define VMA_ASSERT(expr) assert(expr)
  1337. #else
  1338. #define VMA_ASSERT(expr)
  1339. #endif
  1340. #endif
  1341. // Assert that will be called very often, like inside data structures e.g. operator[].
  1342. // Making it non-empty can make program slow.
  1343. #ifndef VMA_HEAVY_ASSERT
  1344. #ifdef _DEBUG
  1345. #define VMA_HEAVY_ASSERT(expr) //VMA_ASSERT(expr)
  1346. #else
  1347. #define VMA_HEAVY_ASSERT(expr)
  1348. #endif
  1349. #endif
  1350. #ifndef VMA_NULL
  1351. // Value used as null pointer. Define it to e.g.: nullptr, NULL, 0, (void*)0.
  1352. #define VMA_NULL nullptr
  1353. #endif
  1354. #ifndef VMA_ALIGN_OF
  1355. #define VMA_ALIGN_OF(type) (__alignof(type))
  1356. #endif
  1357. #ifndef VMA_SYSTEM_ALIGNED_MALLOC
  1358. #if defined(_WIN32)
  1359. #define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) (_aligned_malloc((size), (alignment)))
  1360. #else
  1361. #define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) (aligned_alloc((alignment), (size) ))
  1362. #endif
  1363. #endif
  1364. #ifndef VMA_SYSTEM_FREE
  1365. #if defined(_WIN32)
  1366. #define VMA_SYSTEM_FREE(ptr) _aligned_free(ptr)
  1367. #else
  1368. #define VMA_SYSTEM_FREE(ptr) free(ptr)
  1369. #endif
  1370. #endif
  1371. #ifndef VMA_MIN
  1372. #define VMA_MIN(v1, v2) (std::min((v1), (v2)))
  1373. #endif
  1374. #ifndef VMA_MAX
  1375. #define VMA_MAX(v1, v2) (std::max((v1), (v2)))
  1376. #endif
  1377. #ifndef VMA_SWAP
  1378. #define VMA_SWAP(v1, v2) std::swap((v1), (v2))
  1379. #endif
  1380. #ifndef VMA_SORT
  1381. #define VMA_SORT(beg, end, cmp) std::sort(beg, end, cmp)
  1382. #endif
  1383. #ifndef VMA_DEBUG_LOG
  1384. #define VMA_DEBUG_LOG(format, ...)
  1385. /*
  1386. #define VMA_DEBUG_LOG(format, ...) do { \
  1387. printf(format, __VA_ARGS__); \
  1388. printf("\n"); \
  1389. } while(false)
  1390. */
  1391. #endif
  1392. // Define this macro to 1 to enable functions: vmaBuildStatsString, vmaFreeStatsString.
  1393. #if VMA_STATS_STRING_ENABLED
  1394. static inline void VmaUint32ToStr(char* outStr, size_t strLen, uint32_t num)
  1395. {
  1396. snprintf(outStr, strLen, "%u", static_cast<unsigned int>(num));
  1397. }
  1398. static inline void VmaUint64ToStr(char* outStr, size_t strLen, uint64_t num)
  1399. {
  1400. snprintf(outStr, strLen, "%llu", static_cast<unsigned long long>(num));
  1401. }
  1402. static inline void VmaPtrToStr(char* outStr, size_t strLen, const void* ptr)
  1403. {
  1404. snprintf(outStr, strLen, "%p", ptr);
  1405. }
  1406. #endif
  1407. #ifndef VMA_MUTEX
  1408. class VmaMutex
  1409. {
  1410. public:
  1411. VmaMutex() { }
  1412. ~VmaMutex() { }
  1413. void Lock() { m_Mutex.lock(); }
  1414. void Unlock() { m_Mutex.unlock(); }
  1415. private:
  1416. std::mutex m_Mutex;
  1417. };
  1418. #define VMA_MUTEX VmaMutex
  1419. #endif
  1420. /*
  1421. If providing your own implementation, you need to implement a subset of std::atomic:
  1422. - Constructor(uint32_t desired)
  1423. - uint32_t load() const
  1424. - void store(uint32_t desired)
  1425. - bool compare_exchange_weak(uint32_t& expected, uint32_t desired)
  1426. */
  1427. #ifndef VMA_ATOMIC_UINT32
  1428. #define VMA_ATOMIC_UINT32 std::atomic<uint32_t>
  1429. #endif
  1430. #ifndef VMA_BEST_FIT
  1431. /**
  1432. Main parameter for function assessing how good is a free suballocation for a new
  1433. allocation request.
  1434. - Set to 1 to use Best-Fit algorithm - prefer smaller blocks, as close to the
  1435. size of requested allocations as possible.
  1436. - Set to 0 to use Worst-Fit algorithm - prefer larger blocks, as large as
  1437. possible.
  1438. Experiments in special testing environment showed that Best-Fit algorithm is
  1439. better.
  1440. */
  1441. #define VMA_BEST_FIT (1)
  1442. #endif
  1443. #ifndef VMA_DEBUG_ALWAYS_DEDICATED_MEMORY
  1444. /**
  1445. Every allocation will have its own memory block.
  1446. Define to 1 for debugging purposes only.
  1447. */
  1448. #define VMA_DEBUG_ALWAYS_DEDICATED_MEMORY (0)
  1449. #endif
  1450. #ifndef VMA_DEBUG_ALIGNMENT
  1451. /**
  1452. Minimum alignment of all suballocations, in bytes.
  1453. Set to more than 1 for debugging purposes only. Must be power of two.
  1454. */
  1455. #define VMA_DEBUG_ALIGNMENT (1)
  1456. #endif
  1457. #ifndef VMA_DEBUG_MARGIN
  1458. /**
  1459. Minimum margin between suballocations, in bytes.
  1460. Set nonzero for debugging purposes only.
  1461. */
  1462. #define VMA_DEBUG_MARGIN (0)
  1463. #endif
  1464. #ifndef VMA_DEBUG_GLOBAL_MUTEX
  1465. /**
  1466. Set this to 1 for debugging purposes only, to enable single mutex protecting all
  1467. entry calls to the library. Can be useful for debugging multithreading issues.
  1468. */
  1469. #define VMA_DEBUG_GLOBAL_MUTEX (0)
  1470. #endif
  1471. #ifndef VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY
  1472. /**
  1473. Minimum value for VkPhysicalDeviceLimits::bufferImageGranularity.
  1474. Set to more than 1 for debugging purposes only. Must be power of two.
  1475. */
  1476. #define VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY (1)
  1477. #endif
  1478. #ifndef VMA_SMALL_HEAP_MAX_SIZE
  1479. /// Maximum size of a memory heap in Vulkan to consider it "small".
  1480. #define VMA_SMALL_HEAP_MAX_SIZE (512 * 1024 * 1024)
  1481. #endif
  1482. #ifndef VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE
  1483. /// Default size of a block allocated as single VkDeviceMemory from a "large" heap.
  1484. #define VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE (256 * 1024 * 1024)
  1485. #endif
  1486. #ifndef VMA_DEFAULT_SMALL_HEAP_BLOCK_SIZE
  1487. /// Default size of a block allocated as single VkDeviceMemory from a "small" heap.
  1488. #define VMA_DEFAULT_SMALL_HEAP_BLOCK_SIZE (64 * 1024 * 1024)
  1489. #endif
  1490. static const uint32_t VMA_FRAME_INDEX_LOST = UINT32_MAX;
  1491. /*******************************************************************************
  1492. END OF CONFIGURATION
  1493. */
  1494. static VkAllocationCallbacks VmaEmptyAllocationCallbacks = {
  1495. VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL };
  1496. // Returns number of bits set to 1 in (v).
  1497. static inline uint32_t VmaCountBitsSet(uint32_t v)
  1498. {
  1499. uint32_t c = v - ((v >> 1) & 0x55555555);
  1500. c = ((c >> 2) & 0x33333333) + (c & 0x33333333);
  1501. c = ((c >> 4) + c) & 0x0F0F0F0F;
  1502. c = ((c >> 8) + c) & 0x00FF00FF;
  1503. c = ((c >> 16) + c) & 0x0000FFFF;
  1504. return c;
  1505. }
  1506. // Aligns given value up to nearest multiply of align value. For example: VmaAlignUp(11, 8) = 16.
  1507. // Use types like uint32_t, uint64_t as T.
  1508. template <typename T>
  1509. static inline T VmaAlignUp(T val, T align)
  1510. {
  1511. return (val + align - 1) / align * align;
  1512. }
  1513. // Division with mathematical rounding to nearest number.
  1514. template <typename T>
  1515. inline T VmaRoundDiv(T x, T y)
  1516. {
  1517. return (x + (y / (T)2)) / y;
  1518. }
  1519. #ifndef VMA_SORT
  1520. template<typename Iterator, typename Compare>
  1521. Iterator VmaQuickSortPartition(Iterator beg, Iterator end, Compare cmp)
  1522. {
  1523. Iterator centerValue = end; --centerValue;
  1524. Iterator insertIndex = beg;
  1525. for(Iterator memTypeIndex = beg; memTypeIndex < centerValue; ++memTypeIndex)
  1526. {
  1527. if(cmp(*memTypeIndex, *centerValue))
  1528. {
  1529. if(insertIndex != memTypeIndex)
  1530. {
  1531. VMA_SWAP(*memTypeIndex, *insertIndex);
  1532. }
  1533. ++insertIndex;
  1534. }
  1535. }
  1536. if(insertIndex != centerValue)
  1537. {
  1538. VMA_SWAP(*insertIndex, *centerValue);
  1539. }
  1540. return insertIndex;
  1541. }
  1542. template<typename Iterator, typename Compare>
  1543. void VmaQuickSort(Iterator beg, Iterator end, Compare cmp)
  1544. {
  1545. if(beg < end)
  1546. {
  1547. Iterator it = VmaQuickSortPartition<Iterator, Compare>(beg, end, cmp);
  1548. VmaQuickSort<Iterator, Compare>(beg, it, cmp);
  1549. VmaQuickSort<Iterator, Compare>(it + 1, end, cmp);
  1550. }
  1551. }
  1552. #define VMA_SORT(beg, end, cmp) VmaQuickSort(beg, end, cmp)
  1553. #endif // #ifndef VMA_SORT
  1554. /*
  1555. Returns true if two memory blocks occupy overlapping pages.
  1556. ResourceA must be in less memory offset than ResourceB.
  1557. Algorithm is based on "Vulkan 1.0.39 - A Specification (with all registered Vulkan extensions)"
  1558. chapter 11.6 "Resource Memory Association", paragraph "Buffer-Image Granularity".
  1559. */
  1560. static inline bool VmaBlocksOnSamePage(
  1561. VkDeviceSize resourceAOffset,
  1562. VkDeviceSize resourceASize,
  1563. VkDeviceSize resourceBOffset,
  1564. VkDeviceSize pageSize)
  1565. {
  1566. VMA_ASSERT(resourceAOffset + resourceASize <= resourceBOffset && resourceASize > 0 && pageSize > 0);
  1567. VkDeviceSize resourceAEnd = resourceAOffset + resourceASize - 1;
  1568. VkDeviceSize resourceAEndPage = resourceAEnd & ~(pageSize - 1);
  1569. VkDeviceSize resourceBStart = resourceBOffset;
  1570. VkDeviceSize resourceBStartPage = resourceBStart & ~(pageSize - 1);
  1571. return resourceAEndPage == resourceBStartPage;
  1572. }
  1573. enum VmaSuballocationType
  1574. {
  1575. VMA_SUBALLOCATION_TYPE_FREE = 0,
  1576. VMA_SUBALLOCATION_TYPE_UNKNOWN = 1,
  1577. VMA_SUBALLOCATION_TYPE_BUFFER = 2,
  1578. VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN = 3,
  1579. VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR = 4,
  1580. VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL = 5,
  1581. VMA_SUBALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF
  1582. };
  1583. /*
  1584. Returns true if given suballocation types could conflict and must respect
  1585. VkPhysicalDeviceLimits::bufferImageGranularity. They conflict if one is buffer
  1586. or linear image and another one is optimal image. If type is unknown, behave
  1587. conservatively.
  1588. */
  1589. static inline bool VmaIsBufferImageGranularityConflict(
  1590. VmaSuballocationType suballocType1,
  1591. VmaSuballocationType suballocType2)
  1592. {
  1593. if(suballocType1 > suballocType2)
  1594. {
  1595. VMA_SWAP(suballocType1, suballocType2);
  1596. }
  1597. switch(suballocType1)
  1598. {
  1599. case VMA_SUBALLOCATION_TYPE_FREE:
  1600. return false;
  1601. case VMA_SUBALLOCATION_TYPE_UNKNOWN:
  1602. return true;
  1603. case VMA_SUBALLOCATION_TYPE_BUFFER:
  1604. return
  1605. suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN ||
  1606. suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
  1607. case VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN:
  1608. return
  1609. suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN ||
  1610. suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR ||
  1611. suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
  1612. case VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR:
  1613. return
  1614. suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
  1615. case VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL:
  1616. return false;
  1617. default:
  1618. VMA_ASSERT(0);
  1619. return true;
  1620. }
  1621. }
  1622. // Helper RAII class to lock a mutex in constructor and unlock it in destructor (at the end of scope).
  1623. struct VmaMutexLock
  1624. {
  1625. public:
  1626. VmaMutexLock(VMA_MUTEX& mutex, bool useMutex) :
  1627. m_pMutex(useMutex ? &mutex : VMA_NULL)
  1628. {
  1629. if(m_pMutex)
  1630. {
  1631. m_pMutex->Lock();
  1632. }
  1633. }
  1634. ~VmaMutexLock()
  1635. {
  1636. if(m_pMutex)
  1637. {
  1638. m_pMutex->Unlock();
  1639. }
  1640. }
  1641. private:
  1642. VMA_MUTEX* m_pMutex;
  1643. };
  1644. #if VMA_DEBUG_GLOBAL_MUTEX
  1645. static VMA_MUTEX gDebugGlobalMutex;
  1646. #define VMA_DEBUG_GLOBAL_MUTEX_LOCK VmaMutexLock debugGlobalMutexLock(gDebugGlobalMutex, true);
  1647. #else
  1648. #define VMA_DEBUG_GLOBAL_MUTEX_LOCK
  1649. #endif
  1650. // Minimum size of a free suballocation to register it in the free suballocation collection.
  1651. static const VkDeviceSize VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER = 16;
  1652. /*
  1653. Performs binary search and returns iterator to first element that is greater or
  1654. equal to (key), according to comparison (cmp).
  1655. Cmp should return true if first argument is less than second argument.
  1656. Returned value is the found element, if present in the collection or place where
  1657. new element with value (key) should be inserted.
  1658. */
  1659. template <typename IterT, typename KeyT, typename CmpT>
  1660. static IterT VmaBinaryFindFirstNotLess(IterT beg, IterT end, const KeyT &key, CmpT cmp)
  1661. {
  1662. size_t down = 0, up = (end - beg);
  1663. while(down < up)
  1664. {
  1665. const size_t mid = (down + up) / 2;
  1666. if(cmp(*(beg+mid), key))
  1667. {
  1668. down = mid + 1;
  1669. }
  1670. else
  1671. {
  1672. up = mid;
  1673. }
  1674. }
  1675. return beg + down;
  1676. }
  1677. ////////////////////////////////////////////////////////////////////////////////
  1678. // Memory allocation
  1679. static void* VmaMalloc(const VkAllocationCallbacks* pAllocationCallbacks, size_t size, size_t alignment)
  1680. {
  1681. if((pAllocationCallbacks != VMA_NULL) &&
  1682. (pAllocationCallbacks->pfnAllocation != VMA_NULL))
  1683. {
  1684. return (*pAllocationCallbacks->pfnAllocation)(
  1685. pAllocationCallbacks->pUserData,
  1686. size,
  1687. alignment,
  1688. VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
  1689. }
  1690. else
  1691. {
  1692. return VMA_SYSTEM_ALIGNED_MALLOC(size, alignment);
  1693. }
  1694. }
  1695. static void VmaFree(const VkAllocationCallbacks* pAllocationCallbacks, void* ptr)
  1696. {
  1697. if((pAllocationCallbacks != VMA_NULL) &&
  1698. (pAllocationCallbacks->pfnFree != VMA_NULL))
  1699. {
  1700. (*pAllocationCallbacks->pfnFree)(pAllocationCallbacks->pUserData, ptr);
  1701. }
  1702. else
  1703. {
  1704. VMA_SYSTEM_FREE(ptr);
  1705. }
  1706. }
  1707. template<typename T>
  1708. static T* VmaAllocate(const VkAllocationCallbacks* pAllocationCallbacks)
  1709. {
  1710. return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T), VMA_ALIGN_OF(T));
  1711. }
  1712. template<typename T>
  1713. static T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, size_t count)
  1714. {
  1715. return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T) * count, VMA_ALIGN_OF(T));
  1716. }
  1717. #define vma_new(allocator, type) new(VmaAllocate<type>(allocator))(type)
  1718. #define vma_new_array(allocator, type, count) new(VmaAllocateArray<type>((allocator), (count)))(type)
  1719. template<typename T>
  1720. static void vma_delete(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr)
  1721. {
  1722. ptr->~T();
  1723. VmaFree(pAllocationCallbacks, ptr);
  1724. }
  1725. template<typename T>
  1726. static void vma_delete_array(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr, size_t count)
  1727. {
  1728. if(ptr != VMA_NULL)
  1729. {
  1730. for(size_t i = count; i--; )
  1731. {
  1732. ptr[i].~T();
  1733. }
  1734. VmaFree(pAllocationCallbacks, ptr);
  1735. }
  1736. }
  1737. // STL-compatible allocator.
  1738. template<typename T>
  1739. class VmaStlAllocator
  1740. {
  1741. public:
  1742. const VkAllocationCallbacks* const m_pCallbacks;
  1743. typedef T value_type;
  1744. VmaStlAllocator(const VkAllocationCallbacks* pCallbacks) : m_pCallbacks(pCallbacks) { }
  1745. template<typename U> VmaStlAllocator(const VmaStlAllocator<U>& src) : m_pCallbacks(src.m_pCallbacks) { }
  1746. T* allocate(size_t n) { return VmaAllocateArray<T>(m_pCallbacks, n); }
  1747. void deallocate(T* p, size_t n) { VmaFree(m_pCallbacks, p); }
  1748. template<typename U>
  1749. bool operator==(const VmaStlAllocator<U>& rhs) const
  1750. {
  1751. return m_pCallbacks == rhs.m_pCallbacks;
  1752. }
  1753. template<typename U>
  1754. bool operator!=(const VmaStlAllocator<U>& rhs) const
  1755. {
  1756. return m_pCallbacks != rhs.m_pCallbacks;
  1757. }
  1758. VmaStlAllocator& operator=(const VmaStlAllocator& x) = delete;
  1759. };
  1760. #if VMA_USE_STL_VECTOR
  1761. #define VmaVector std::vector
  1762. template<typename T, typename allocatorT>
  1763. static void VmaVectorInsert(std::vector<T, allocatorT>& vec, size_t index, const T& item)
  1764. {
  1765. vec.insert(vec.begin() + index, item);
  1766. }
  1767. template<typename T, typename allocatorT>
  1768. static void VmaVectorRemove(std::vector<T, allocatorT>& vec, size_t index)
  1769. {
  1770. vec.erase(vec.begin() + index);
  1771. }
  1772. #else // #if VMA_USE_STL_VECTOR
  1773. /* Class with interface compatible with subset of std::vector.
  1774. T must be POD because constructors and destructors are not called and memcpy is
  1775. used for these objects. */
  1776. template<typename T, typename AllocatorT>
  1777. class VmaVector
  1778. {
  1779. public:
  1780. typedef T value_type;
  1781. VmaVector(const AllocatorT& allocator) :
  1782. m_Allocator(allocator),
  1783. m_pArray(VMA_NULL),
  1784. m_Count(0),
  1785. m_Capacity(0)
  1786. {
  1787. }
  1788. VmaVector(size_t count, const AllocatorT& allocator) :
  1789. m_Allocator(allocator),
  1790. m_pArray(count ? (T*)VmaAllocateArray<T>(allocator.m_pCallbacks, count) : VMA_NULL),
  1791. m_Count(count),
  1792. m_Capacity(count)
  1793. {
  1794. }
  1795. VmaVector(const VmaVector<T, AllocatorT>& src) :
  1796. m_Allocator(src.m_Allocator),
  1797. m_pArray(src.m_Count ? (T*)VmaAllocateArray<T>(src.m_Allocator.m_pCallbacks, src.m_Count) : VMA_NULL),
  1798. m_Count(src.m_Count),
  1799. m_Capacity(src.m_Count)
  1800. {
  1801. if(m_Count != 0)
  1802. {
  1803. memcpy(m_pArray, src.m_pArray, m_Count * sizeof(T));
  1804. }
  1805. }
  1806. ~VmaVector()
  1807. {
  1808. VmaFree(m_Allocator.m_pCallbacks, m_pArray);
  1809. }
  1810. VmaVector& operator=(const VmaVector<T, AllocatorT>& rhs)
  1811. {
  1812. if(&rhs != this)
  1813. {
  1814. resize(rhs.m_Count);
  1815. if(m_Count != 0)
  1816. {
  1817. memcpy(m_pArray, rhs.m_pArray, m_Count * sizeof(T));
  1818. }
  1819. }
  1820. return *this;
  1821. }
  1822. bool empty() const { return m_Count == 0; }
  1823. size_t size() const { return m_Count; }
  1824. T* data() { return m_pArray; }
  1825. const T* data() const { return m_pArray; }
  1826. T& operator[](size_t index)
  1827. {
  1828. VMA_HEAVY_ASSERT(index < m_Count);
  1829. return m_pArray[index];
  1830. }
  1831. const T& operator[](size_t index) const
  1832. {
  1833. VMA_HEAVY_ASSERT(index < m_Count);
  1834. return m_pArray[index];
  1835. }
  1836. T& front()
  1837. {
  1838. VMA_HEAVY_ASSERT(m_Count > 0);
  1839. return m_pArray[0];
  1840. }
  1841. const T& front() const
  1842. {
  1843. VMA_HEAVY_ASSERT(m_Count > 0);
  1844. return m_pArray[0];
  1845. }
  1846. T& back()
  1847. {
  1848. VMA_HEAVY_ASSERT(m_Count > 0);
  1849. return m_pArray[m_Count - 1];
  1850. }
  1851. const T& back() const
  1852. {
  1853. VMA_HEAVY_ASSERT(m_Count > 0);
  1854. return m_pArray[m_Count - 1];
  1855. }
  1856. void reserve(size_t newCapacity, bool freeMemory = false)
  1857. {
  1858. newCapacity = VMA_MAX(newCapacity, m_Count);
  1859. if((newCapacity < m_Capacity) && !freeMemory)
  1860. {
  1861. newCapacity = m_Capacity;
  1862. }
  1863. if(newCapacity != m_Capacity)
  1864. {
  1865. T* const newArray = newCapacity ? VmaAllocateArray<T>(m_Allocator, newCapacity) : VMA_NULL;
  1866. if(m_Count != 0)
  1867. {
  1868. memcpy(newArray, m_pArray, m_Count * sizeof(T));
  1869. }
  1870. VmaFree(m_Allocator.m_pCallbacks, m_pArray);
  1871. m_Capacity = newCapacity;
  1872. m_pArray = newArray;
  1873. }
  1874. }
  1875. void resize(size_t newCount, bool freeMemory = false)
  1876. {
  1877. size_t newCapacity = m_Capacity;
  1878. if(newCount > m_Capacity)
  1879. {
  1880. newCapacity = VMA_MAX(newCount, VMA_MAX(m_Capacity * 3 / 2, (size_t)8));
  1881. }
  1882. else if(freeMemory)
  1883. {
  1884. newCapacity = newCount;
  1885. }
  1886. if(newCapacity != m_Capacity)
  1887. {
  1888. T* const newArray = newCapacity ? VmaAllocateArray<T>(m_Allocator.m_pCallbacks, newCapacity) : VMA_NULL;
  1889. const size_t elementsToCopy = VMA_MIN(m_Count, newCount);
  1890. if(elementsToCopy != 0)
  1891. {
  1892. memcpy(newArray, m_pArray, elementsToCopy * sizeof(T));
  1893. }
  1894. VmaFree(m_Allocator.m_pCallbacks, m_pArray);
  1895. m_Capacity = newCapacity;
  1896. m_pArray = newArray;
  1897. }
  1898. m_Count = newCount;
  1899. }
  1900. void clear(bool freeMemory = false)
  1901. {
  1902. resize(0, freeMemory);
  1903. }
  1904. void insert(size_t index, const T& src)
  1905. {
  1906. VMA_HEAVY_ASSERT(index <= m_Count);
  1907. const size_t oldCount = size();
  1908. resize(oldCount + 1);
  1909. if(index < oldCount)
  1910. {
  1911. memmove(m_pArray + (index + 1), m_pArray + index, (oldCount - index) * sizeof(T));
  1912. }
  1913. m_pArray[index] = src;
  1914. }
  1915. void remove(size_t index)
  1916. {
  1917. VMA_HEAVY_ASSERT(index < m_Count);
  1918. const size_t oldCount = size();
  1919. if(index < oldCount - 1)
  1920. {
  1921. memmove(m_pArray + index, m_pArray + (index + 1), (oldCount - index - 1) * sizeof(T));
  1922. }
  1923. resize(oldCount - 1);
  1924. }
  1925. void push_back(const T& src)
  1926. {
  1927. const size_t newIndex = size();
  1928. resize(newIndex + 1);
  1929. m_pArray[newIndex] = src;
  1930. }
  1931. void pop_back()
  1932. {
  1933. VMA_HEAVY_ASSERT(m_Count > 0);
  1934. resize(size() - 1);
  1935. }
  1936. void push_front(const T& src)
  1937. {
  1938. insert(0, src);
  1939. }
  1940. void pop_front()
  1941. {
  1942. VMA_HEAVY_ASSERT(m_Count > 0);
  1943. remove(0);
  1944. }
  1945. typedef T* iterator;
  1946. iterator begin() { return m_pArray; }
  1947. iterator end() { return m_pArray + m_Count; }
  1948. private:
  1949. AllocatorT m_Allocator;
  1950. T* m_pArray;
  1951. size_t m_Count;
  1952. size_t m_Capacity;
  1953. };
  1954. template<typename T, typename allocatorT>
  1955. static void VmaVectorInsert(VmaVector<T, allocatorT>& vec, size_t index, const T& item)
  1956. {
  1957. vec.insert(index, item);
  1958. }
  1959. template<typename T, typename allocatorT>
  1960. static void VmaVectorRemove(VmaVector<T, allocatorT>& vec, size_t index)
  1961. {
  1962. vec.remove(index);
  1963. }
  1964. #endif // #if VMA_USE_STL_VECTOR
  1965. template<typename CmpLess, typename VectorT>
  1966. size_t VmaVectorInsertSorted(VectorT& vector, const typename VectorT::value_type& value)
  1967. {
  1968. const size_t indexToInsert = VmaBinaryFindFirstNotLess(
  1969. vector.data(),
  1970. vector.data() + vector.size(),
  1971. value,
  1972. CmpLess()) - vector.data();
  1973. VmaVectorInsert(vector, indexToInsert, value);
  1974. return indexToInsert;
  1975. }
  1976. template<typename CmpLess, typename VectorT>
  1977. bool VmaVectorRemoveSorted(VectorT& vector, const typename VectorT::value_type& value)
  1978. {
  1979. CmpLess comparator;
  1980. typename VectorT::iterator it = VmaBinaryFindFirstNotLess(
  1981. vector.begin(),
  1982. vector.end(),
  1983. value,
  1984. comparator);
  1985. if((it != vector.end()) && !comparator(*it, value) && !comparator(value, *it))
  1986. {
  1987. size_t indexToRemove = it - vector.begin();
  1988. VmaVectorRemove(vector, indexToRemove);
  1989. return true;
  1990. }
  1991. return false;
  1992. }
  1993. template<typename CmpLess, typename VectorT>
  1994. size_t VmaVectorFindSorted(const VectorT& vector, const typename VectorT::value_type& value)
  1995. {
  1996. CmpLess comparator;
  1997. typename VectorT::iterator it = VmaBinaryFindFirstNotLess(
  1998. vector.data(),
  1999. vector.data() + vector.size(),
  2000. value,
  2001. comparator);
  2002. if(it != vector.size() && !comparator(*it, value) && !comparator(value, *it))
  2003. {
  2004. return it - vector.begin();
  2005. }
  2006. else
  2007. {
  2008. return vector.size();
  2009. }
  2010. }
  2011. ////////////////////////////////////////////////////////////////////////////////
  2012. // class VmaPoolAllocator
  2013. /*
  2014. Allocator for objects of type T using a list of arrays (pools) to speed up
  2015. allocation. Number of elements that can be allocated is not bounded because
  2016. allocator can create multiple blocks.
  2017. */
  2018. template<typename T>
  2019. class VmaPoolAllocator
  2020. {
  2021. public:
  2022. VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, size_t itemsPerBlock);
  2023. ~VmaPoolAllocator();
  2024. void Clear();
  2025. T* Alloc();
  2026. void Free(T* ptr);
  2027. private:
  2028. union Item
  2029. {
  2030. uint32_t NextFreeIndex;
  2031. T Value;
  2032. };
  2033. struct ItemBlock
  2034. {
  2035. Item* pItems;
  2036. uint32_t FirstFreeIndex;
  2037. };
  2038. const VkAllocationCallbacks* m_pAllocationCallbacks;
  2039. size_t m_ItemsPerBlock;
  2040. VmaVector< ItemBlock, VmaStlAllocator<ItemBlock> > m_ItemBlocks;
  2041. ItemBlock& CreateNewBlock();
  2042. };
  2043. template<typename T>
  2044. VmaPoolAllocator<T>::VmaPoolAllocator(const VkAllocationCallbacks* pAllocationCallbacks, size_t itemsPerBlock) :
  2045. m_pAllocationCallbacks(pAllocationCallbacks),
  2046. m_ItemsPerBlock(itemsPerBlock),
  2047. m_ItemBlocks(VmaStlAllocator<ItemBlock>(pAllocationCallbacks))
  2048. {
  2049. VMA_ASSERT(itemsPerBlock > 0);
  2050. }
  2051. template<typename T>
  2052. VmaPoolAllocator<T>::~VmaPoolAllocator()
  2053. {
  2054. Clear();
  2055. }
  2056. template<typename T>
  2057. void VmaPoolAllocator<T>::Clear()
  2058. {
  2059. for(size_t i = m_ItemBlocks.size(); i--; )
  2060. vma_delete_array(m_pAllocationCallbacks, m_ItemBlocks[i].pItems, m_ItemsPerBlock);
  2061. m_ItemBlocks.clear();
  2062. }
  2063. template<typename T>
  2064. T* VmaPoolAllocator<T>::Alloc()
  2065. {
  2066. for(size_t i = m_ItemBlocks.size(); i--; )
  2067. {
  2068. ItemBlock& block = m_ItemBlocks[i];
  2069. // This block has some free items: Use first one.
  2070. if(block.FirstFreeIndex != UINT32_MAX)
  2071. {
  2072. Item* const pItem = &block.pItems[block.FirstFreeIndex];
  2073. block.FirstFreeIndex = pItem->NextFreeIndex;
  2074. return &pItem->Value;
  2075. }
  2076. }
  2077. // No block has free item: Create new one and use it.
  2078. ItemBlock& newBlock = CreateNewBlock();
  2079. Item* const pItem = &newBlock.pItems[0];
  2080. newBlock.FirstFreeIndex = pItem->NextFreeIndex;
  2081. return &pItem->Value;
  2082. }
  2083. template<typename T>
  2084. void VmaPoolAllocator<T>::Free(T* ptr)
  2085. {
  2086. // Search all memory blocks to find ptr.
  2087. for(size_t i = 0; i < m_ItemBlocks.size(); ++i)
  2088. {
  2089. ItemBlock& block = m_ItemBlocks[i];
  2090. // Casting to union.
  2091. Item* pItemPtr;
  2092. memcpy(&pItemPtr, &ptr, sizeof(pItemPtr));
  2093. // Check if pItemPtr is in address range of this block.
  2094. if((pItemPtr >= block.pItems) && (pItemPtr < block.pItems + m_ItemsPerBlock))
  2095. {
  2096. const uint32_t index = static_cast<uint32_t>(pItemPtr - block.pItems);
  2097. pItemPtr->NextFreeIndex = block.FirstFreeIndex;
  2098. block.FirstFreeIndex = index;
  2099. return;
  2100. }
  2101. }
  2102. VMA_ASSERT(0 && "Pointer doesn't belong to this memory pool.");
  2103. }
  2104. template<typename T>
  2105. typename VmaPoolAllocator<T>::ItemBlock& VmaPoolAllocator<T>::CreateNewBlock()
  2106. {
  2107. ItemBlock newBlock = {
  2108. vma_new_array(m_pAllocationCallbacks, Item, m_ItemsPerBlock), 0 };
  2109. m_ItemBlocks.push_back(newBlock);
  2110. // Setup singly-linked list of all free items in this block.
  2111. for(uint32_t i = 0; i < m_ItemsPerBlock - 1; ++i)
  2112. newBlock.pItems[i].NextFreeIndex = i + 1;
  2113. newBlock.pItems[m_ItemsPerBlock - 1].NextFreeIndex = UINT32_MAX;
  2114. return m_ItemBlocks.back();
  2115. }
  2116. ////////////////////////////////////////////////////////////////////////////////
  2117. // class VmaRawList, VmaList
  2118. #if VMA_USE_STL_LIST
  2119. #define VmaList std::list
  2120. #else // #if VMA_USE_STL_LIST
  2121. template<typename T>
  2122. struct VmaListItem
  2123. {
  2124. VmaListItem* pPrev;
  2125. VmaListItem* pNext;
  2126. T Value;
  2127. };
  2128. // Doubly linked list.
  2129. template<typename T>
  2130. class VmaRawList
  2131. {
  2132. public:
  2133. typedef VmaListItem<T> ItemType;
  2134. VmaRawList(const VkAllocationCallbacks* pAllocationCallbacks);
  2135. ~VmaRawList();
  2136. void Clear();
  2137. size_t GetCount() const { return m_Count; }
  2138. bool IsEmpty() const { return m_Count == 0; }
  2139. ItemType* Front() { return m_pFront; }
  2140. const ItemType* Front() const { return m_pFront; }
  2141. ItemType* Back() { return m_pBack; }
  2142. const ItemType* Back() const { return m_pBack; }
  2143. ItemType* PushBack();
  2144. ItemType* PushFront();
  2145. ItemType* PushBack(const T& value);
  2146. ItemType* PushFront(const T& value);
  2147. void PopBack();
  2148. void PopFront();
  2149. // Item can be null - it means PushBack.
  2150. ItemType* InsertBefore(ItemType* pItem);
  2151. // Item can be null - it means PushFront.
  2152. ItemType* InsertAfter(ItemType* pItem);
  2153. ItemType* InsertBefore(ItemType* pItem, const T& value);
  2154. ItemType* InsertAfter(ItemType* pItem, const T& value);
  2155. void Remove(ItemType* pItem);
  2156. private:
  2157. const VkAllocationCallbacks* const m_pAllocationCallbacks;
  2158. VmaPoolAllocator<ItemType> m_ItemAllocator;
  2159. ItemType* m_pFront;
  2160. ItemType* m_pBack;
  2161. size_t m_Count;
  2162. // Declared not defined, to block copy constructor and assignment operator.
  2163. VmaRawList(const VmaRawList<T>& src);
  2164. VmaRawList<T>& operator=(const VmaRawList<T>& rhs);
  2165. };
  2166. template<typename T>
  2167. VmaRawList<T>::VmaRawList(const VkAllocationCallbacks* pAllocationCallbacks) :
  2168. m_pAllocationCallbacks(pAllocationCallbacks),
  2169. m_ItemAllocator(pAllocationCallbacks, 128),
  2170. m_pFront(VMA_NULL),
  2171. m_pBack(VMA_NULL),
  2172. m_Count(0)
  2173. {
  2174. }
  2175. template<typename T>
  2176. VmaRawList<T>::~VmaRawList()
  2177. {
  2178. // Intentionally not calling Clear, because that would be unnecessary
  2179. // computations to return all items to m_ItemAllocator as free.
  2180. }
  2181. template<typename T>
  2182. void VmaRawList<T>::Clear()
  2183. {
  2184. if(IsEmpty() == false)
  2185. {
  2186. ItemType* pItem = m_pBack;
  2187. while(pItem != VMA_NULL)
  2188. {
  2189. ItemType* const pPrevItem = pItem->pPrev;
  2190. m_ItemAllocator.Free(pItem);
  2191. pItem = pPrevItem;
  2192. }
  2193. m_pFront = VMA_NULL;
  2194. m_pBack = VMA_NULL;
  2195. m_Count = 0;
  2196. }
  2197. }
  2198. template<typename T>
  2199. VmaListItem<T>* VmaRawList<T>::PushBack()
  2200. {
  2201. ItemType* const pNewItem = m_ItemAllocator.Alloc();
  2202. pNewItem->pNext = VMA_NULL;
  2203. if(IsEmpty())
  2204. {
  2205. pNewItem->pPrev = VMA_NULL;
  2206. m_pFront = pNewItem;
  2207. m_pBack = pNewItem;
  2208. m_Count = 1;
  2209. }
  2210. else
  2211. {
  2212. pNewItem->pPrev = m_pBack;
  2213. m_pBack->pNext = pNewItem;
  2214. m_pBack = pNewItem;
  2215. ++m_Count;
  2216. }
  2217. return pNewItem;
  2218. }
  2219. template<typename T>
  2220. VmaListItem<T>* VmaRawList<T>::PushFront()
  2221. {
  2222. ItemType* const pNewItem = m_ItemAllocator.Alloc();
  2223. pNewItem->pPrev = VMA_NULL;
  2224. if(IsEmpty())
  2225. {
  2226. pNewItem->pNext = VMA_NULL;
  2227. m_pFront = pNewItem;
  2228. m_pBack = pNewItem;
  2229. m_Count = 1;
  2230. }
  2231. else
  2232. {
  2233. pNewItem->pNext = m_pFront;
  2234. m_pFront->pPrev = pNewItem;
  2235. m_pFront = pNewItem;
  2236. ++m_Count;
  2237. }
  2238. return pNewItem;
  2239. }
  2240. template<typename T>
  2241. VmaListItem<T>* VmaRawList<T>::PushBack(const T& value)
  2242. {
  2243. ItemType* const pNewItem = PushBack();
  2244. pNewItem->Value = value;
  2245. return pNewItem;
  2246. }
  2247. template<typename T>
  2248. VmaListItem<T>* VmaRawList<T>::PushFront(const T& value)
  2249. {
  2250. ItemType* const pNewItem = PushFront();
  2251. pNewItem->Value = value;
  2252. return pNewItem;
  2253. }
  2254. template<typename T>
  2255. void VmaRawList<T>::PopBack()
  2256. {
  2257. VMA_HEAVY_ASSERT(m_Count > 0);
  2258. ItemType* const pBackItem = m_pBack;
  2259. ItemType* const pPrevItem = pBackItem->pPrev;
  2260. if(pPrevItem != VMA_NULL)
  2261. {
  2262. pPrevItem->pNext = VMA_NULL;
  2263. }
  2264. m_pBack = pPrevItem;
  2265. m_ItemAllocator.Free(pBackItem);
  2266. --m_Count;
  2267. }
  2268. template<typename T>
  2269. void VmaRawList<T>::PopFront()
  2270. {
  2271. VMA_HEAVY_ASSERT(m_Count > 0);
  2272. ItemType* const pFrontItem = m_pFront;
  2273. ItemType* const pNextItem = pFrontItem->pNext;
  2274. if(pNextItem != VMA_NULL)
  2275. {
  2276. pNextItem->pPrev = VMA_NULL;
  2277. }
  2278. m_pFront = pNextItem;
  2279. m_ItemAllocator.Free(pFrontItem);
  2280. --m_Count;
  2281. }
  2282. template<typename T>
  2283. void VmaRawList<T>::Remove(ItemType* pItem)
  2284. {
  2285. VMA_HEAVY_ASSERT(pItem != VMA_NULL);
  2286. VMA_HEAVY_ASSERT(m_Count > 0);
  2287. if(pItem->pPrev != VMA_NULL)
  2288. {
  2289. pItem->pPrev->pNext = pItem->pNext;
  2290. }
  2291. else
  2292. {
  2293. VMA_HEAVY_ASSERT(m_pFront == pItem);
  2294. m_pFront = pItem->pNext;
  2295. }
  2296. if(pItem->pNext != VMA_NULL)
  2297. {
  2298. pItem->pNext->pPrev = pItem->pPrev;
  2299. }
  2300. else
  2301. {
  2302. VMA_HEAVY_ASSERT(m_pBack == pItem);
  2303. m_pBack = pItem->pPrev;
  2304. }
  2305. m_ItemAllocator.Free(pItem);
  2306. --m_Count;
  2307. }
  2308. template<typename T>
  2309. VmaListItem<T>* VmaRawList<T>::InsertBefore(ItemType* pItem)
  2310. {
  2311. if(pItem != VMA_NULL)
  2312. {
  2313. ItemType* const prevItem = pItem->pPrev;
  2314. ItemType* const newItem = m_ItemAllocator.Alloc();
  2315. newItem->pPrev = prevItem;
  2316. newItem->pNext = pItem;
  2317. pItem->pPrev = newItem;
  2318. if(prevItem != VMA_NULL)
  2319. {
  2320. prevItem->pNext = newItem;
  2321. }
  2322. else
  2323. {
  2324. VMA_HEAVY_ASSERT(m_pFront == pItem);
  2325. m_pFront = newItem;
  2326. }
  2327. ++m_Count;
  2328. return newItem;
  2329. }
  2330. else
  2331. return PushBack();
  2332. }
  2333. template<typename T>
  2334. VmaListItem<T>* VmaRawList<T>::InsertAfter(ItemType* pItem)
  2335. {
  2336. if(pItem != VMA_NULL)
  2337. {
  2338. ItemType* const nextItem = pItem->pNext;
  2339. ItemType* const newItem = m_ItemAllocator.Alloc();
  2340. newItem->pNext = nextItem;
  2341. newItem->pPrev = pItem;
  2342. pItem->pNext = newItem;
  2343. if(nextItem != VMA_NULL)
  2344. {
  2345. nextItem->pPrev = newItem;
  2346. }
  2347. else
  2348. {
  2349. VMA_HEAVY_ASSERT(m_pBack == pItem);
  2350. m_pBack = newItem;
  2351. }
  2352. ++m_Count;
  2353. return newItem;
  2354. }
  2355. else
  2356. return PushFront();
  2357. }
  2358. template<typename T>
  2359. VmaListItem<T>* VmaRawList<T>::InsertBefore(ItemType* pItem, const T& value)
  2360. {
  2361. ItemType* const newItem = InsertBefore(pItem);
  2362. newItem->Value = value;
  2363. return newItem;
  2364. }
  2365. template<typename T>
  2366. VmaListItem<T>* VmaRawList<T>::InsertAfter(ItemType* pItem, const T& value)
  2367. {
  2368. ItemType* const newItem = InsertAfter(pItem);
  2369. newItem->Value = value;
  2370. return newItem;
  2371. }
  2372. template<typename T, typename AllocatorT>
  2373. class VmaList
  2374. {
  2375. public:
  2376. class iterator
  2377. {
  2378. public:
  2379. iterator() :
  2380. m_pList(VMA_NULL),
  2381. m_pItem(VMA_NULL)
  2382. {
  2383. }
  2384. T& operator*() const
  2385. {
  2386. VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
  2387. return m_pItem->Value;
  2388. }
  2389. T* operator->() const
  2390. {
  2391. VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
  2392. return &m_pItem->Value;
  2393. }
  2394. iterator& operator++()
  2395. {
  2396. VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
  2397. m_pItem = m_pItem->pNext;
  2398. return *this;
  2399. }
  2400. iterator& operator--()
  2401. {
  2402. if(m_pItem != VMA_NULL)
  2403. {
  2404. m_pItem = m_pItem->pPrev;
  2405. }
  2406. else
  2407. {
  2408. VMA_HEAVY_ASSERT(!m_pList.IsEmpty());
  2409. m_pItem = m_pList->Back();
  2410. }
  2411. return *this;
  2412. }
  2413. iterator operator++(int)
  2414. {
  2415. iterator result = *this;
  2416. ++*this;
  2417. return result;
  2418. }
  2419. iterator operator--(int)
  2420. {
  2421. iterator result = *this;
  2422. --*this;
  2423. return result;
  2424. }
  2425. bool operator==(const iterator& rhs) const
  2426. {
  2427. VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
  2428. return m_pItem == rhs.m_pItem;
  2429. }
  2430. bool operator!=(const iterator& rhs) const
  2431. {
  2432. VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
  2433. return m_pItem != rhs.m_pItem;
  2434. }
  2435. private:
  2436. VmaRawList<T>* m_pList;
  2437. VmaListItem<T>* m_pItem;
  2438. iterator(VmaRawList<T>* pList, VmaListItem<T>* pItem) :
  2439. m_pList(pList),
  2440. m_pItem(pItem)
  2441. {
  2442. }
  2443. friend class VmaList<T, AllocatorT>;
  2444. };
  2445. class const_iterator
  2446. {
  2447. public:
  2448. const_iterator() :
  2449. m_pList(VMA_NULL),
  2450. m_pItem(VMA_NULL)
  2451. {
  2452. }
  2453. const_iterator(const iterator& src) :
  2454. m_pList(src.m_pList),
  2455. m_pItem(src.m_pItem)
  2456. {
  2457. }
  2458. const T& operator*() const
  2459. {
  2460. VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
  2461. return m_pItem->Value;
  2462. }
  2463. const T* operator->() const
  2464. {
  2465. VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
  2466. return &m_pItem->Value;
  2467. }
  2468. const_iterator& operator++()
  2469. {
  2470. VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
  2471. m_pItem = m_pItem->pNext;
  2472. return *this;
  2473. }
  2474. const_iterator& operator--()
  2475. {
  2476. if(m_pItem != VMA_NULL)
  2477. {
  2478. m_pItem = m_pItem->pPrev;
  2479. }
  2480. else
  2481. {
  2482. VMA_HEAVY_ASSERT(!m_pList->IsEmpty());
  2483. m_pItem = m_pList->Back();
  2484. }
  2485. return *this;
  2486. }
  2487. const_iterator operator++(int)
  2488. {
  2489. const_iterator result = *this;
  2490. ++*this;
  2491. return result;
  2492. }
  2493. const_iterator operator--(int)
  2494. {
  2495. const_iterator result = *this;
  2496. --*this;
  2497. return result;
  2498. }
  2499. bool operator==(const const_iterator& rhs) const
  2500. {
  2501. VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
  2502. return m_pItem == rhs.m_pItem;
  2503. }
  2504. bool operator!=(const const_iterator& rhs) const
  2505. {
  2506. VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
  2507. return m_pItem != rhs.m_pItem;
  2508. }
  2509. private:
  2510. const_iterator(const VmaRawList<T>* pList, const VmaListItem<T>* pItem) :
  2511. m_pList(pList),
  2512. m_pItem(pItem)
  2513. {
  2514. }
  2515. const VmaRawList<T>* m_pList;
  2516. const VmaListItem<T>* m_pItem;
  2517. friend class VmaList<T, AllocatorT>;
  2518. };
  2519. VmaList(const AllocatorT& allocator) : m_RawList(allocator.m_pCallbacks) { }
  2520. bool empty() const { return m_RawList.IsEmpty(); }
  2521. size_t size() const { return m_RawList.GetCount(); }
  2522. iterator begin() { return iterator(&m_RawList, m_RawList.Front()); }
  2523. iterator end() { return iterator(&m_RawList, VMA_NULL); }
  2524. const_iterator cbegin() const { return const_iterator(&m_RawList, m_RawList.Front()); }
  2525. const_iterator cend() const { return const_iterator(&m_RawList, VMA_NULL); }
  2526. void clear() { m_RawList.Clear(); }
  2527. void push_back(const T& value) { m_RawList.PushBack(value); }
  2528. void erase(iterator it) { m_RawList.Remove(it.m_pItem); }
  2529. iterator insert(iterator it, const T& value) { return iterator(&m_RawList, m_RawList.InsertBefore(it.m_pItem, value)); }
  2530. private:
  2531. VmaRawList<T> m_RawList;
  2532. };
  2533. #endif // #if VMA_USE_STL_LIST
  2534. ////////////////////////////////////////////////////////////////////////////////
  2535. // class VmaMap
  2536. // Unused in this version.
  2537. #if 0
  2538. #if VMA_USE_STL_UNORDERED_MAP
  2539. #define VmaPair std::pair
  2540. #define VMA_MAP_TYPE(KeyT, ValueT) \
  2541. std::unordered_map< KeyT, ValueT, std::hash<KeyT>, std::equal_to<KeyT>, VmaStlAllocator< std::pair<KeyT, ValueT> > >
  2542. #else // #if VMA_USE_STL_UNORDERED_MAP
  2543. template<typename T1, typename T2>
  2544. struct VmaPair
  2545. {
  2546. T1 first;
  2547. T2 second;
  2548. VmaPair() : first(), second() { }
  2549. VmaPair(const T1& firstSrc, const T2& secondSrc) : first(firstSrc), second(secondSrc) { }
  2550. };
  2551. /* Class compatible with subset of interface of std::unordered_map.
  2552. KeyT, ValueT must be POD because they will be stored in VmaVector.
  2553. */
  2554. template<typename KeyT, typename ValueT>
  2555. class VmaMap
  2556. {
  2557. public:
  2558. typedef VmaPair<KeyT, ValueT> PairType;
  2559. typedef PairType* iterator;
  2560. VmaMap(const VmaStlAllocator<PairType>& allocator) : m_Vector(allocator) { }
  2561. iterator begin() { return m_Vector.begin(); }
  2562. iterator end() { return m_Vector.end(); }
  2563. void insert(const PairType& pair);
  2564. iterator find(const KeyT& key);
  2565. void erase(iterator it);
  2566. private:
  2567. VmaVector< PairType, VmaStlAllocator<PairType> > m_Vector;
  2568. };
  2569. #define VMA_MAP_TYPE(KeyT, ValueT) VmaMap<KeyT, ValueT>
  2570. template<typename FirstT, typename SecondT>
  2571. struct VmaPairFirstLess
  2572. {
  2573. bool operator()(const VmaPair<FirstT, SecondT>& lhs, const VmaPair<FirstT, SecondT>& rhs) const
  2574. {
  2575. return lhs.first < rhs.first;
  2576. }
  2577. bool operator()(const VmaPair<FirstT, SecondT>& lhs, const FirstT& rhsFirst) const
  2578. {
  2579. return lhs.first < rhsFirst;
  2580. }
  2581. };
  2582. template<typename KeyT, typename ValueT>
  2583. void VmaMap<KeyT, ValueT>::insert(const PairType& pair)
  2584. {
  2585. const size_t indexToInsert = VmaBinaryFindFirstNotLess(
  2586. m_Vector.data(),
  2587. m_Vector.data() + m_Vector.size(),
  2588. pair,
  2589. VmaPairFirstLess<KeyT, ValueT>()) - m_Vector.data();
  2590. VmaVectorInsert(m_Vector, indexToInsert, pair);
  2591. }
  2592. template<typename KeyT, typename ValueT>
  2593. VmaPair<KeyT, ValueT>* VmaMap<KeyT, ValueT>::find(const KeyT& key)
  2594. {
  2595. PairType* it = VmaBinaryFindFirstNotLess(
  2596. m_Vector.data(),
  2597. m_Vector.data() + m_Vector.size(),
  2598. key,
  2599. VmaPairFirstLess<KeyT, ValueT>());
  2600. if((it != m_Vector.end()) && (it->first == key))
  2601. {
  2602. return it;
  2603. }
  2604. else
  2605. {
  2606. return m_Vector.end();
  2607. }
  2608. }
  2609. template<typename KeyT, typename ValueT>
  2610. void VmaMap<KeyT, ValueT>::erase(iterator it)
  2611. {
  2612. VmaVectorRemove(m_Vector, it - m_Vector.begin());
  2613. }
  2614. #endif // #if VMA_USE_STL_UNORDERED_MAP
  2615. #endif // #if 0
  2616. ////////////////////////////////////////////////////////////////////////////////
  2617. class VmaDeviceMemoryBlock;
  2618. struct VmaAllocation_T
  2619. {
  2620. private:
  2621. static const uint8_t MAP_COUNT_FLAG_PERSISTENT_MAP = 0x80;
  2622. enum FLAGS
  2623. {
  2624. FLAG_USER_DATA_STRING = 0x01,
  2625. };
  2626. public:
  2627. enum ALLOCATION_TYPE
  2628. {
  2629. ALLOCATION_TYPE_NONE,
  2630. ALLOCATION_TYPE_BLOCK,
  2631. ALLOCATION_TYPE_DEDICATED,
  2632. };
  2633. VmaAllocation_T(uint32_t currentFrameIndex, bool userDataString) :
  2634. m_Alignment(1),
  2635. m_Size(0),
  2636. m_pUserData(VMA_NULL),
  2637. m_LastUseFrameIndex(currentFrameIndex),
  2638. m_Type((uint8_t)ALLOCATION_TYPE_NONE),
  2639. m_SuballocationType((uint8_t)VMA_SUBALLOCATION_TYPE_UNKNOWN),
  2640. m_MapCount(0),
  2641. m_Flags(userDataString ? (uint8_t)FLAG_USER_DATA_STRING : 0)
  2642. {
  2643. }
  2644. ~VmaAllocation_T()
  2645. {
  2646. VMA_ASSERT((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) == 0 && "Allocation was not unmapped before destruction.");
  2647. // Check if owned string was freed.
  2648. VMA_ASSERT(m_pUserData == VMA_NULL);
  2649. }
  2650. void InitBlockAllocation(
  2651. VmaPool hPool,
  2652. VmaDeviceMemoryBlock* block,
  2653. VkDeviceSize offset,
  2654. VkDeviceSize alignment,
  2655. VkDeviceSize size,
  2656. VmaSuballocationType suballocationType,
  2657. bool mapped,
  2658. bool canBecomeLost)
  2659. {
  2660. VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE);
  2661. VMA_ASSERT(block != VMA_NULL);
  2662. m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK;
  2663. m_Alignment = alignment;
  2664. m_Size = size;
  2665. m_MapCount = mapped ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0;
  2666. m_SuballocationType = (uint8_t)suballocationType;
  2667. m_BlockAllocation.m_hPool = hPool;
  2668. m_BlockAllocation.m_Block = block;
  2669. m_BlockAllocation.m_Offset = offset;
  2670. m_BlockAllocation.m_CanBecomeLost = canBecomeLost;
  2671. }
  2672. void InitLost()
  2673. {
  2674. VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE);
  2675. VMA_ASSERT(m_LastUseFrameIndex.load() == VMA_FRAME_INDEX_LOST);
  2676. m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK;
  2677. m_BlockAllocation.m_hPool = VK_NULL_HANDLE;
  2678. m_BlockAllocation.m_Block = VMA_NULL;
  2679. m_BlockAllocation.m_Offset = 0;
  2680. m_BlockAllocation.m_CanBecomeLost = true;
  2681. }
  2682. void ChangeBlockAllocation(
  2683. VmaDeviceMemoryBlock* block,
  2684. VkDeviceSize offset)
  2685. {
  2686. VMA_ASSERT(block != VMA_NULL);
  2687. VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK);
  2688. m_BlockAllocation.m_Block = block;
  2689. m_BlockAllocation.m_Offset = offset;
  2690. }
  2691. // pMappedData not null means allocation is created with MAPPED flag.
  2692. void InitDedicatedAllocation(
  2693. uint32_t memoryTypeIndex,
  2694. VkDeviceMemory hMemory,
  2695. VmaSuballocationType suballocationType,
  2696. void* pMappedData,
  2697. VkDeviceSize size)
  2698. {
  2699. VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE);
  2700. VMA_ASSERT(hMemory != VK_NULL_HANDLE);
  2701. m_Type = (uint8_t)ALLOCATION_TYPE_DEDICATED;
  2702. m_Alignment = 0;
  2703. m_Size = size;
  2704. m_SuballocationType = (uint8_t)suballocationType;
  2705. m_MapCount = (pMappedData != VMA_NULL) ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0;
  2706. m_DedicatedAllocation.m_MemoryTypeIndex = memoryTypeIndex;
  2707. m_DedicatedAllocation.m_hMemory = hMemory;
  2708. m_DedicatedAllocation.m_pMappedData = pMappedData;
  2709. }
  2710. ALLOCATION_TYPE GetType() const { return (ALLOCATION_TYPE)m_Type; }
  2711. VkDeviceSize GetAlignment() const { return m_Alignment; }
  2712. VkDeviceSize GetSize() const { return m_Size; }
  2713. bool IsUserDataString() const { return (m_Flags & FLAG_USER_DATA_STRING) != 0; }
  2714. void* GetUserData() const { return m_pUserData; }
  2715. void SetUserData(VmaAllocator hAllocator, void* pUserData);
  2716. VmaSuballocationType GetSuballocationType() const { return (VmaSuballocationType)m_SuballocationType; }
  2717. VmaDeviceMemoryBlock* GetBlock() const
  2718. {
  2719. VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK);
  2720. return m_BlockAllocation.m_Block;
  2721. }
  2722. VkDeviceSize GetOffset() const;
  2723. VkDeviceMemory GetMemory() const;
  2724. uint32_t GetMemoryTypeIndex() const;
  2725. bool IsPersistentMap() const { return (m_MapCount & MAP_COUNT_FLAG_PERSISTENT_MAP) != 0; }
  2726. void* GetMappedData() const;
  2727. bool CanBecomeLost() const;
  2728. VmaPool GetPool() const;
  2729. uint32_t GetLastUseFrameIndex() const
  2730. {
  2731. return m_LastUseFrameIndex.load();
  2732. }
  2733. bool CompareExchangeLastUseFrameIndex(uint32_t& expected, uint32_t desired)
  2734. {
  2735. return m_LastUseFrameIndex.compare_exchange_weak(expected, desired);
  2736. }
  2737. /*
  2738. - If hAllocation.LastUseFrameIndex + frameInUseCount < allocator.CurrentFrameIndex,
  2739. makes it lost by setting LastUseFrameIndex = VMA_FRAME_INDEX_LOST and returns true.
  2740. - Else, returns false.
  2741. If hAllocation is already lost, assert - you should not call it then.
  2742. If hAllocation was not created with CAN_BECOME_LOST_BIT, assert.
  2743. */
  2744. bool MakeLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);
  2745. void DedicatedAllocCalcStatsInfo(VmaStatInfo& outInfo)
  2746. {
  2747. VMA_ASSERT(m_Type == ALLOCATION_TYPE_DEDICATED);
  2748. outInfo.blockCount = 1;
  2749. outInfo.allocationCount = 1;
  2750. outInfo.unusedRangeCount = 0;
  2751. outInfo.usedBytes = m_Size;
  2752. outInfo.unusedBytes = 0;
  2753. outInfo.allocationSizeMin = outInfo.allocationSizeMax = m_Size;
  2754. outInfo.unusedRangeSizeMin = UINT64_MAX;
  2755. outInfo.unusedRangeSizeMax = 0;
  2756. }
  2757. void BlockAllocMap();
  2758. void BlockAllocUnmap();
  2759. VkResult DedicatedAllocMap(VmaAllocator hAllocator, void** ppData);
  2760. void DedicatedAllocUnmap(VmaAllocator hAllocator);
  2761. private:
  2762. VkDeviceSize m_Alignment;
  2763. VkDeviceSize m_Size;
  2764. void* m_pUserData;
  2765. VMA_ATOMIC_UINT32 m_LastUseFrameIndex;
  2766. uint8_t m_Type; // ALLOCATION_TYPE
  2767. uint8_t m_SuballocationType; // VmaSuballocationType
  2768. // Bit 0x80 is set when allocation was created with VMA_ALLOCATION_CREATE_MAPPED_BIT.
  2769. // Bits with mask 0x7F, used only when ALLOCATION_TYPE_DEDICATED, are reference counter for vmaMapMemory()/vmaUnmapMemory().
  2770. uint8_t m_MapCount;
  2771. uint8_t m_Flags; // enum FLAGS
  2772. // Allocation out of VmaDeviceMemoryBlock.
  2773. struct BlockAllocation
  2774. {
  2775. VmaPool m_hPool; // Null if belongs to general memory.
  2776. VmaDeviceMemoryBlock* m_Block;
  2777. VkDeviceSize m_Offset;
  2778. bool m_CanBecomeLost;
  2779. };
  2780. // Allocation for an object that has its own private VkDeviceMemory.
  2781. struct DedicatedAllocation
  2782. {
  2783. uint32_t m_MemoryTypeIndex;
  2784. VkDeviceMemory m_hMemory;
  2785. void* m_pMappedData; // Not null means memory is mapped.
  2786. };
  2787. union
  2788. {
  2789. // Allocation out of VmaDeviceMemoryBlock.
  2790. BlockAllocation m_BlockAllocation;
  2791. // Allocation for an object that has its own private VkDeviceMemory.
  2792. DedicatedAllocation m_DedicatedAllocation;
  2793. };
  2794. void FreeUserDataString(VmaAllocator hAllocator);
  2795. };
  2796. /*
  2797. Represents a region of VmaDeviceMemoryBlock that is either assigned and returned as
  2798. allocated memory block or free.
  2799. */
  2800. struct VmaSuballocation
  2801. {
  2802. VkDeviceSize offset;
  2803. VkDeviceSize size;
  2804. VmaAllocation hAllocation;
  2805. VmaSuballocationType type;
  2806. };
  2807. typedef VmaList< VmaSuballocation, VmaStlAllocator<VmaSuballocation> > VmaSuballocationList;
  2808. // Cost of one additional allocation lost, as equivalent in bytes.
  2809. static const VkDeviceSize VMA_LOST_ALLOCATION_COST = 1048576;
  2810. /*
  2811. Parameters of planned allocation inside a VmaDeviceMemoryBlock.
  2812. If canMakeOtherLost was false:
  2813. - item points to a FREE suballocation.
  2814. - itemsToMakeLostCount is 0.
  2815. If canMakeOtherLost was true:
  2816. - item points to first of sequence of suballocations, which are either FREE,
  2817. or point to VmaAllocations that can become lost.
  2818. - itemsToMakeLostCount is the number of VmaAllocations that need to be made lost for
  2819. the requested allocation to succeed.
  2820. */
  2821. struct VmaAllocationRequest
  2822. {
  2823. VkDeviceSize offset;
  2824. VkDeviceSize sumFreeSize; // Sum size of free items that overlap with proposed allocation.
  2825. VkDeviceSize sumItemSize; // Sum size of items to make lost that overlap with proposed allocation.
  2826. VmaSuballocationList::iterator item;
  2827. size_t itemsToMakeLostCount;
  2828. VkDeviceSize CalcCost() const
  2829. {
  2830. return sumItemSize + itemsToMakeLostCount * VMA_LOST_ALLOCATION_COST;
  2831. }
  2832. };
  2833. /*
  2834. Data structure used for bookkeeping of allocations and unused ranges of memory
  2835. in a single VkDeviceMemory block.
  2836. */
  2837. class VmaBlockMetadata
  2838. {
  2839. public:
  2840. VmaBlockMetadata(VmaAllocator hAllocator);
  2841. ~VmaBlockMetadata();
  2842. void Init(VkDeviceSize size);
  2843. // Validates all data structures inside this object. If not valid, returns false.
  2844. bool Validate() const;
  2845. VkDeviceSize GetSize() const { return m_Size; }
  2846. size_t GetAllocationCount() const { return m_Suballocations.size() - m_FreeCount; }
  2847. VkDeviceSize GetSumFreeSize() const { return m_SumFreeSize; }
  2848. VkDeviceSize GetUnusedRangeSizeMax() const;
  2849. // Returns true if this block is empty - contains only single free suballocation.
  2850. bool IsEmpty() const;
  2851. void CalcAllocationStatInfo(VmaStatInfo& outInfo) const;
  2852. void AddPoolStats(VmaPoolStats& inoutStats) const;
  2853. #if VMA_STATS_STRING_ENABLED
  2854. void PrintDetailedMap(class VmaJsonWriter& json) const;
  2855. #endif
  2856. // Creates trivial request for case when block is empty.
  2857. void CreateFirstAllocationRequest(VmaAllocationRequest* pAllocationRequest);
  2858. // Tries to find a place for suballocation with given parameters inside this block.
  2859. // If succeeded, fills pAllocationRequest and returns true.
  2860. // If failed, returns false.
  2861. bool CreateAllocationRequest(
  2862. uint32_t currentFrameIndex,
  2863. uint32_t frameInUseCount,
  2864. VkDeviceSize bufferImageGranularity,
  2865. VkDeviceSize allocSize,
  2866. VkDeviceSize allocAlignment,
  2867. VmaSuballocationType allocType,
  2868. bool canMakeOtherLost,
  2869. VmaAllocationRequest* pAllocationRequest);
  2870. bool MakeRequestedAllocationsLost(
  2871. uint32_t currentFrameIndex,
  2872. uint32_t frameInUseCount,
  2873. VmaAllocationRequest* pAllocationRequest);
  2874. uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);
  2875. // Makes actual allocation based on request. Request must already be checked and valid.
  2876. void Alloc(
  2877. const VmaAllocationRequest& request,
  2878. VmaSuballocationType type,
  2879. VkDeviceSize allocSize,
  2880. VmaAllocation hAllocation);
  2881. // Frees suballocation assigned to given memory region.
  2882. void Free(const VmaAllocation allocation);
  2883. private:
  2884. VkDeviceSize m_Size;
  2885. uint32_t m_FreeCount;
  2886. VkDeviceSize m_SumFreeSize;
  2887. VmaSuballocationList m_Suballocations;
  2888. // Suballocations that are free and have size greater than certain threshold.
  2889. // Sorted by size, ascending.
  2890. VmaVector< VmaSuballocationList::iterator, VmaStlAllocator< VmaSuballocationList::iterator > > m_FreeSuballocationsBySize;
  2891. bool ValidateFreeSuballocationList() const;
  2892. // Checks if requested suballocation with given parameters can be placed in given pFreeSuballocItem.
  2893. // If yes, fills pOffset and returns true. If no, returns false.
  2894. bool CheckAllocation(
  2895. uint32_t currentFrameIndex,
  2896. uint32_t frameInUseCount,
  2897. VkDeviceSize bufferImageGranularity,
  2898. VkDeviceSize allocSize,
  2899. VkDeviceSize allocAlignment,
  2900. VmaSuballocationType allocType,
  2901. VmaSuballocationList::const_iterator suballocItem,
  2902. bool canMakeOtherLost,
  2903. VkDeviceSize* pOffset,
  2904. size_t* itemsToMakeLostCount,
  2905. VkDeviceSize* pSumFreeSize,
  2906. VkDeviceSize* pSumItemSize) const;
  2907. // Given free suballocation, it merges it with following one, which must also be free.
  2908. void MergeFreeWithNext(VmaSuballocationList::iterator item);
  2909. // Releases given suballocation, making it free.
  2910. // Merges it with adjacent free suballocations if applicable.
  2911. // Returns iterator to new free suballocation at this place.
  2912. VmaSuballocationList::iterator FreeSuballocation(VmaSuballocationList::iterator suballocItem);
  2913. // Given free suballocation, it inserts it into sorted list of
  2914. // m_FreeSuballocationsBySize if it's suitable.
  2915. void RegisterFreeSuballocation(VmaSuballocationList::iterator item);
  2916. // Given free suballocation, it removes it from sorted list of
  2917. // m_FreeSuballocationsBySize if it's suitable.
  2918. void UnregisterFreeSuballocation(VmaSuballocationList::iterator item);
  2919. };
  2920. // Helper class that represents mapped memory. Synchronized internally.
  2921. class VmaDeviceMemoryMapping
  2922. {
  2923. public:
  2924. VmaDeviceMemoryMapping();
  2925. ~VmaDeviceMemoryMapping();
  2926. void* GetMappedData() const { return m_pMappedData; }
  2927. // ppData can be null.
  2928. VkResult Map(VmaAllocator hAllocator, VkDeviceMemory hMemory, void **ppData);
  2929. void Unmap(VmaAllocator hAllocator, VkDeviceMemory hMemory);
  2930. private:
  2931. VMA_MUTEX m_Mutex;
  2932. uint32_t m_MapCount;
  2933. void* m_pMappedData;
  2934. };
  2935. /*
  2936. Represents a single block of device memory (`VkDeviceMemory`) with all the
  2937. data about its regions (aka suballocations, `VmaAllocation`), assigned and free.
  2938. Thread-safety: This class must be externally synchronized.
  2939. */
  2940. class VmaDeviceMemoryBlock
  2941. {
  2942. public:
  2943. uint32_t m_MemoryTypeIndex;
  2944. VkDeviceMemory m_hMemory;
  2945. VmaDeviceMemoryMapping m_Mapping;
  2946. VmaBlockMetadata m_Metadata;
  2947. VmaDeviceMemoryBlock(VmaAllocator hAllocator);
  2948. ~VmaDeviceMemoryBlock()
  2949. {
  2950. VMA_ASSERT(m_hMemory == VK_NULL_HANDLE);
  2951. }
  2952. // Always call after construction.
  2953. void Init(
  2954. uint32_t newMemoryTypeIndex,
  2955. VkDeviceMemory newMemory,
  2956. VkDeviceSize newSize);
  2957. // Always call before destruction.
  2958. void Destroy(VmaAllocator allocator);
  2959. // Validates all data structures inside this object. If not valid, returns false.
  2960. bool Validate() const;
  2961. // ppData can be null.
  2962. VkResult Map(VmaAllocator hAllocator, void** ppData);
  2963. void Unmap(VmaAllocator hAllocator);
  2964. };
  2965. struct VmaPointerLess
  2966. {
  2967. bool operator()(const void* lhs, const void* rhs) const
  2968. {
  2969. return lhs < rhs;
  2970. }
  2971. };
  2972. class VmaDefragmentator;
  2973. /*
  2974. Sequence of VmaDeviceMemoryBlock. Represents memory blocks allocated for a specific
  2975. Vulkan memory type.
  2976. Synchronized internally with a mutex.
  2977. */
  2978. struct VmaBlockVector
  2979. {
  2980. VmaBlockVector(
  2981. VmaAllocator hAllocator,
  2982. uint32_t memoryTypeIndex,
  2983. VkDeviceSize preferredBlockSize,
  2984. size_t minBlockCount,
  2985. size_t maxBlockCount,
  2986. VkDeviceSize bufferImageGranularity,
  2987. uint32_t frameInUseCount,
  2988. bool isCustomPool);
  2989. ~VmaBlockVector();
  2990. VkResult CreateMinBlocks();
  2991. uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; }
  2992. VkDeviceSize GetPreferredBlockSize() const { return m_PreferredBlockSize; }
  2993. VkDeviceSize GetBufferImageGranularity() const { return m_BufferImageGranularity; }
  2994. uint32_t GetFrameInUseCount() const { return m_FrameInUseCount; }
  2995. void GetPoolStats(VmaPoolStats* pStats);
  2996. bool IsEmpty() const { return m_Blocks.empty(); }
  2997. VkResult Allocate(
  2998. VmaPool hCurrentPool,
  2999. uint32_t currentFrameIndex,
  3000. const VkMemoryRequirements& vkMemReq,
  3001. const VmaAllocationCreateInfo& createInfo,
  3002. VmaSuballocationType suballocType,
  3003. VmaAllocation* pAllocation);
  3004. void Free(
  3005. VmaAllocation hAllocation);
  3006. // Adds statistics of this BlockVector to pStats.
  3007. void AddStats(VmaStats* pStats);
  3008. #if VMA_STATS_STRING_ENABLED
  3009. void PrintDetailedMap(class VmaJsonWriter& json);
  3010. #endif
  3011. void MakePoolAllocationsLost(
  3012. uint32_t currentFrameIndex,
  3013. size_t* pLostAllocationCount);
  3014. VmaDefragmentator* EnsureDefragmentator(
  3015. VmaAllocator hAllocator,
  3016. uint32_t currentFrameIndex);
  3017. VkResult Defragment(
  3018. VmaDefragmentationStats* pDefragmentationStats,
  3019. VkDeviceSize& maxBytesToMove,
  3020. uint32_t& maxAllocationsToMove);
  3021. void DestroyDefragmentator();
  3022. private:
  3023. friend class VmaDefragmentator;
  3024. const VmaAllocator m_hAllocator;
  3025. const uint32_t m_MemoryTypeIndex;
  3026. const VkDeviceSize m_PreferredBlockSize;
  3027. const size_t m_MinBlockCount;
  3028. const size_t m_MaxBlockCount;
  3029. const VkDeviceSize m_BufferImageGranularity;
  3030. const uint32_t m_FrameInUseCount;
  3031. const bool m_IsCustomPool;
  3032. VMA_MUTEX m_Mutex;
  3033. // Incrementally sorted by sumFreeSize, ascending.
  3034. VmaVector< VmaDeviceMemoryBlock*, VmaStlAllocator<VmaDeviceMemoryBlock*> > m_Blocks;
  3035. /* There can be at most one allocation that is completely empty - a
  3036. hysteresis to avoid pessimistic case of alternating creation and destruction
  3037. of a VkDeviceMemory. */
  3038. bool m_HasEmptyBlock;
  3039. VmaDefragmentator* m_pDefragmentator;
  3040. // Finds and removes given block from vector.
  3041. void Remove(VmaDeviceMemoryBlock* pBlock);
  3042. // Performs single step in sorting m_Blocks. They may not be fully sorted
  3043. // after this call.
  3044. void IncrementallySortBlocks();
  3045. VkResult CreateBlock(VkDeviceSize blockSize, size_t* pNewBlockIndex);
  3046. };
  3047. struct VmaPool_T
  3048. {
  3049. public:
  3050. VmaBlockVector m_BlockVector;
  3051. // Takes ownership.
  3052. VmaPool_T(
  3053. VmaAllocator hAllocator,
  3054. const VmaPoolCreateInfo& createInfo);
  3055. ~VmaPool_T();
  3056. VmaBlockVector& GetBlockVector() { return m_BlockVector; }
  3057. #if VMA_STATS_STRING_ENABLED
  3058. //void PrintDetailedMap(class VmaStringBuilder& sb);
  3059. #endif
  3060. };
  3061. class VmaDefragmentator
  3062. {
  3063. const VmaAllocator m_hAllocator;
  3064. VmaBlockVector* const m_pBlockVector;
  3065. uint32_t m_CurrentFrameIndex;
  3066. VkDeviceSize m_BytesMoved;
  3067. uint32_t m_AllocationsMoved;
  3068. struct AllocationInfo
  3069. {
  3070. VmaAllocation m_hAllocation;
  3071. VkBool32* m_pChanged;
  3072. AllocationInfo() :
  3073. m_hAllocation(VK_NULL_HANDLE),
  3074. m_pChanged(VMA_NULL)
  3075. {
  3076. }
  3077. };
  3078. struct AllocationInfoSizeGreater
  3079. {
  3080. bool operator()(const AllocationInfo& lhs, const AllocationInfo& rhs) const
  3081. {
  3082. return lhs.m_hAllocation->GetSize() > rhs.m_hAllocation->GetSize();
  3083. }
  3084. };
  3085. // Used between AddAllocation and Defragment.
  3086. VmaVector< AllocationInfo, VmaStlAllocator<AllocationInfo> > m_Allocations;
  3087. struct BlockInfo
  3088. {
  3089. VmaDeviceMemoryBlock* m_pBlock;
  3090. bool m_HasNonMovableAllocations;
  3091. VmaVector< AllocationInfo, VmaStlAllocator<AllocationInfo> > m_Allocations;
  3092. BlockInfo(const VkAllocationCallbacks* pAllocationCallbacks) :
  3093. m_pBlock(VMA_NULL),
  3094. m_HasNonMovableAllocations(true),
  3095. m_Allocations(pAllocationCallbacks),
  3096. m_pMappedDataForDefragmentation(VMA_NULL)
  3097. {
  3098. }
  3099. void CalcHasNonMovableAllocations()
  3100. {
  3101. const size_t blockAllocCount = m_pBlock->m_Metadata.GetAllocationCount();
  3102. const size_t defragmentAllocCount = m_Allocations.size();
  3103. m_HasNonMovableAllocations = blockAllocCount != defragmentAllocCount;
  3104. }
  3105. void SortAllocationsBySizeDescecnding()
  3106. {
  3107. VMA_SORT(m_Allocations.begin(), m_Allocations.end(), AllocationInfoSizeGreater());
  3108. }
  3109. VkResult EnsureMapping(VmaAllocator hAllocator, void** ppMappedData);
  3110. void Unmap(VmaAllocator hAllocator);
  3111. private:
  3112. // Not null if mapped for defragmentation only, not originally mapped.
  3113. void* m_pMappedDataForDefragmentation;
  3114. };
  3115. struct BlockPointerLess
  3116. {
  3117. bool operator()(const BlockInfo* pLhsBlockInfo, const VmaDeviceMemoryBlock* pRhsBlock) const
  3118. {
  3119. return pLhsBlockInfo->m_pBlock < pRhsBlock;
  3120. }
  3121. bool operator()(const BlockInfo* pLhsBlockInfo, const BlockInfo* pRhsBlockInfo) const
  3122. {
  3123. return pLhsBlockInfo->m_pBlock < pRhsBlockInfo->m_pBlock;
  3124. }
  3125. };
  3126. // 1. Blocks with some non-movable allocations go first.
  3127. // 2. Blocks with smaller sumFreeSize go first.
  3128. struct BlockInfoCompareMoveDestination
  3129. {
  3130. bool operator()(const BlockInfo* pLhsBlockInfo, const BlockInfo* pRhsBlockInfo) const
  3131. {
  3132. if(pLhsBlockInfo->m_HasNonMovableAllocations && !pRhsBlockInfo->m_HasNonMovableAllocations)
  3133. {
  3134. return true;
  3135. }
  3136. if(!pLhsBlockInfo->m_HasNonMovableAllocations && pRhsBlockInfo->m_HasNonMovableAllocations)
  3137. {
  3138. return false;
  3139. }
  3140. if(pLhsBlockInfo->m_pBlock->m_Metadata.GetSumFreeSize() < pRhsBlockInfo->m_pBlock->m_Metadata.GetSumFreeSize())
  3141. {
  3142. return true;
  3143. }
  3144. return false;
  3145. }
  3146. };
  3147. typedef VmaVector< BlockInfo*, VmaStlAllocator<BlockInfo*> > BlockInfoVector;
  3148. BlockInfoVector m_Blocks;
  3149. VkResult DefragmentRound(
  3150. VkDeviceSize maxBytesToMove,
  3151. uint32_t maxAllocationsToMove);
  3152. static bool MoveMakesSense(
  3153. size_t dstBlockIndex, VkDeviceSize dstOffset,
  3154. size_t srcBlockIndex, VkDeviceSize srcOffset);
  3155. public:
  3156. VmaDefragmentator(
  3157. VmaAllocator hAllocator,
  3158. VmaBlockVector* pBlockVector,
  3159. uint32_t currentFrameIndex);
  3160. ~VmaDefragmentator();
  3161. VkDeviceSize GetBytesMoved() const { return m_BytesMoved; }
  3162. uint32_t GetAllocationsMoved() const { return m_AllocationsMoved; }
  3163. void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged);
  3164. VkResult Defragment(
  3165. VkDeviceSize maxBytesToMove,
  3166. uint32_t maxAllocationsToMove);
  3167. };
  3168. // Main allocator object.
  3169. struct VmaAllocator_T
  3170. {
  3171. bool m_UseMutex;
  3172. bool m_UseKhrDedicatedAllocation;
  3173. VkDevice m_hDevice;
  3174. bool m_AllocationCallbacksSpecified;
  3175. VkAllocationCallbacks m_AllocationCallbacks;
  3176. VmaDeviceMemoryCallbacks m_DeviceMemoryCallbacks;
  3177. // Number of bytes free out of limit, or VK_WHOLE_SIZE if not limit for that heap.
  3178. VkDeviceSize m_HeapSizeLimit[VK_MAX_MEMORY_HEAPS];
  3179. VMA_MUTEX m_HeapSizeLimitMutex;
  3180. VkPhysicalDeviceProperties m_PhysicalDeviceProperties;
  3181. VkPhysicalDeviceMemoryProperties m_MemProps;
  3182. // Default pools.
  3183. VmaBlockVector* m_pBlockVectors[VK_MAX_MEMORY_TYPES];
  3184. // Each vector is sorted by memory (handle value).
  3185. typedef VmaVector< VmaAllocation, VmaStlAllocator<VmaAllocation> > AllocationVectorType;
  3186. AllocationVectorType* m_pDedicatedAllocations[VK_MAX_MEMORY_TYPES];
  3187. VMA_MUTEX m_DedicatedAllocationsMutex[VK_MAX_MEMORY_TYPES];
  3188. VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo);
  3189. ~VmaAllocator_T();
  3190. const VkAllocationCallbacks* GetAllocationCallbacks() const
  3191. {
  3192. return m_AllocationCallbacksSpecified ? &m_AllocationCallbacks : 0;
  3193. }
  3194. const VmaVulkanFunctions& GetVulkanFunctions() const
  3195. {
  3196. return m_VulkanFunctions;
  3197. }
  3198. VkDeviceSize GetBufferImageGranularity() const
  3199. {
  3200. return VMA_MAX(
  3201. static_cast<VkDeviceSize>(VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY),
  3202. m_PhysicalDeviceProperties.limits.bufferImageGranularity);
  3203. }
  3204. uint32_t GetMemoryHeapCount() const { return m_MemProps.memoryHeapCount; }
  3205. uint32_t GetMemoryTypeCount() const { return m_MemProps.memoryTypeCount; }
  3206. uint32_t MemoryTypeIndexToHeapIndex(uint32_t memTypeIndex) const
  3207. {
  3208. VMA_ASSERT(memTypeIndex < m_MemProps.memoryTypeCount);
  3209. return m_MemProps.memoryTypes[memTypeIndex].heapIndex;
  3210. }
  3211. void GetBufferMemoryRequirements(
  3212. VkBuffer hBuffer,
  3213. VkMemoryRequirements& memReq,
  3214. bool& requiresDedicatedAllocation,
  3215. bool& prefersDedicatedAllocation) const;
  3216. void GetImageMemoryRequirements(
  3217. VkImage hImage,
  3218. VkMemoryRequirements& memReq,
  3219. bool& requiresDedicatedAllocation,
  3220. bool& prefersDedicatedAllocation) const;
  3221. // Main allocation function.
  3222. VkResult AllocateMemory(
  3223. const VkMemoryRequirements& vkMemReq,
  3224. bool requiresDedicatedAllocation,
  3225. bool prefersDedicatedAllocation,
  3226. VkBuffer dedicatedBuffer,
  3227. VkImage dedicatedImage,
  3228. const VmaAllocationCreateInfo& createInfo,
  3229. VmaSuballocationType suballocType,
  3230. VmaAllocation* pAllocation);
  3231. // Main deallocation function.
  3232. void FreeMemory(const VmaAllocation allocation);
  3233. void CalculateStats(VmaStats* pStats);
  3234. #if VMA_STATS_STRING_ENABLED
  3235. void PrintDetailedMap(class VmaJsonWriter& json);
  3236. #endif
  3237. VkResult Defragment(
  3238. VmaAllocation* pAllocations,
  3239. size_t allocationCount,
  3240. VkBool32* pAllocationsChanged,
  3241. const VmaDefragmentationInfo* pDefragmentationInfo,
  3242. VmaDefragmentationStats* pDefragmentationStats);
  3243. void GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo);
  3244. VkResult CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPool* pPool);
  3245. void DestroyPool(VmaPool pool);
  3246. void GetPoolStats(VmaPool pool, VmaPoolStats* pPoolStats);
  3247. void SetCurrentFrameIndex(uint32_t frameIndex);
  3248. void MakePoolAllocationsLost(
  3249. VmaPool hPool,
  3250. size_t* pLostAllocationCount);
  3251. void CreateLostAllocation(VmaAllocation* pAllocation);
  3252. VkResult AllocateVulkanMemory(const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory);
  3253. void FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, VkDeviceMemory hMemory);
  3254. VkResult Map(VmaAllocation hAllocation, void** ppData);
  3255. void Unmap(VmaAllocation hAllocation);
  3256. private:
  3257. VkDeviceSize m_PreferredLargeHeapBlockSize;
  3258. VkDeviceSize m_PreferredSmallHeapBlockSize;
  3259. VkPhysicalDevice m_PhysicalDevice;
  3260. VMA_ATOMIC_UINT32 m_CurrentFrameIndex;
  3261. VMA_MUTEX m_PoolsMutex;
  3262. // Protected by m_PoolsMutex. Sorted by pointer value.
  3263. VmaVector<VmaPool, VmaStlAllocator<VmaPool> > m_Pools;
  3264. VmaVulkanFunctions m_VulkanFunctions;
  3265. void ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunctions);
  3266. VkDeviceSize CalcPreferredBlockSize(uint32_t memTypeIndex);
  3267. VkResult AllocateMemoryOfType(
  3268. const VkMemoryRequirements& vkMemReq,
  3269. bool dedicatedAllocation,
  3270. VkBuffer dedicatedBuffer,
  3271. VkImage dedicatedImage,
  3272. const VmaAllocationCreateInfo& createInfo,
  3273. uint32_t memTypeIndex,
  3274. VmaSuballocationType suballocType,
  3275. VmaAllocation* pAllocation);
  3276. // Allocates and registers new VkDeviceMemory specifically for single allocation.
  3277. VkResult AllocateDedicatedMemory(
  3278. VkDeviceSize size,
  3279. VmaSuballocationType suballocType,
  3280. uint32_t memTypeIndex,
  3281. bool map,
  3282. bool isUserDataString,
  3283. void* pUserData,
  3284. VkBuffer dedicatedBuffer,
  3285. VkImage dedicatedImage,
  3286. VmaAllocation* pAllocation);
  3287. // Tries to free pMemory as Dedicated Memory. Returns true if found and freed.
  3288. void FreeDedicatedMemory(VmaAllocation allocation);
  3289. };
  3290. ////////////////////////////////////////////////////////////////////////////////
  3291. // Memory allocation #2 after VmaAllocator_T definition
  3292. static void* VmaMalloc(VmaAllocator hAllocator, size_t size, size_t alignment)
  3293. {
  3294. return VmaMalloc(&hAllocator->m_AllocationCallbacks, size, alignment);
  3295. }
  3296. static void VmaFree(VmaAllocator hAllocator, void* ptr)
  3297. {
  3298. VmaFree(&hAllocator->m_AllocationCallbacks, ptr);
  3299. }
  3300. template<typename T>
  3301. static T* VmaAllocate(VmaAllocator hAllocator)
  3302. {
  3303. return (T*)VmaMalloc(hAllocator, sizeof(T), VMA_ALIGN_OF(T));
  3304. }
  3305. template<typename T>
  3306. static T* VmaAllocateArray(VmaAllocator hAllocator, size_t count)
  3307. {
  3308. return (T*)VmaMalloc(hAllocator, sizeof(T) * count, VMA_ALIGN_OF(T));
  3309. }
  3310. template<typename T>
  3311. static void vma_delete(VmaAllocator hAllocator, T* ptr)
  3312. {
  3313. if(ptr != VMA_NULL)
  3314. {
  3315. ptr->~T();
  3316. VmaFree(hAllocator, ptr);
  3317. }
  3318. }
  3319. template<typename T>
  3320. static void vma_delete_array(VmaAllocator hAllocator, T* ptr, size_t count)
  3321. {
  3322. if(ptr != VMA_NULL)
  3323. {
  3324. for(size_t i = count; i--; )
  3325. ptr[i].~T();
  3326. VmaFree(hAllocator, ptr);
  3327. }
  3328. }
  3329. ////////////////////////////////////////////////////////////////////////////////
  3330. // VmaStringBuilder
  3331. #if VMA_STATS_STRING_ENABLED
  3332. class VmaStringBuilder
  3333. {
  3334. public:
  3335. VmaStringBuilder(VmaAllocator alloc) : m_Data(VmaStlAllocator<char>(alloc->GetAllocationCallbacks())) { }
  3336. size_t GetLength() const { return m_Data.size(); }
  3337. const char* GetData() const { return m_Data.data(); }
  3338. void Add(char ch) { m_Data.push_back(ch); }
  3339. void Add(const char* pStr);
  3340. void AddNewLine() { Add('\n'); }
  3341. void AddNumber(uint32_t num);
  3342. void AddNumber(uint64_t num);
  3343. void AddPointer(const void* ptr);
  3344. private:
  3345. VmaVector< char, VmaStlAllocator<char> > m_Data;
  3346. };
  3347. void VmaStringBuilder::Add(const char* pStr)
  3348. {
  3349. const size_t strLen = strlen(pStr);
  3350. if(strLen > 0)
  3351. {
  3352. const size_t oldCount = m_Data.size();
  3353. m_Data.resize(oldCount + strLen);
  3354. memcpy(m_Data.data() + oldCount, pStr, strLen);
  3355. }
  3356. }
  3357. void VmaStringBuilder::AddNumber(uint32_t num)
  3358. {
  3359. char buf[11];
  3360. VmaUint32ToStr(buf, sizeof(buf), num);
  3361. Add(buf);
  3362. }
  3363. void VmaStringBuilder::AddNumber(uint64_t num)
  3364. {
  3365. char buf[21];
  3366. VmaUint64ToStr(buf, sizeof(buf), num);
  3367. Add(buf);
  3368. }
  3369. void VmaStringBuilder::AddPointer(const void* ptr)
  3370. {
  3371. char buf[21];
  3372. VmaPtrToStr(buf, sizeof(buf), ptr);
  3373. Add(buf);
  3374. }
  3375. #endif // #if VMA_STATS_STRING_ENABLED
  3376. ////////////////////////////////////////////////////////////////////////////////
  3377. // VmaJsonWriter
  3378. #if VMA_STATS_STRING_ENABLED
  3379. class VmaJsonWriter
  3380. {
  3381. public:
  3382. VmaJsonWriter(const VkAllocationCallbacks* pAllocationCallbacks, VmaStringBuilder& sb);
  3383. ~VmaJsonWriter();
  3384. void BeginObject(bool singleLine = false);
  3385. void EndObject();
  3386. void BeginArray(bool singleLine = false);
  3387. void EndArray();
  3388. void WriteString(const char* pStr);
  3389. void BeginString(const char* pStr = VMA_NULL);
  3390. void ContinueString(const char* pStr);
  3391. void ContinueString(uint32_t n);
  3392. void ContinueString(uint64_t n);
  3393. void ContinueString_Pointer(const void* ptr);
  3394. void EndString(const char* pStr = VMA_NULL);
  3395. void WriteNumber(uint32_t n);
  3396. void WriteNumber(uint64_t n);
  3397. void WriteBool(bool b);
  3398. void WriteNull();
  3399. private:
  3400. static const char* const INDENT;
  3401. enum COLLECTION_TYPE
  3402. {
  3403. COLLECTION_TYPE_OBJECT,
  3404. COLLECTION_TYPE_ARRAY,
  3405. };
  3406. struct StackItem
  3407. {
  3408. COLLECTION_TYPE type;
  3409. uint32_t valueCount;
  3410. bool singleLineMode;
  3411. };
  3412. VmaStringBuilder& m_SB;
  3413. VmaVector< StackItem, VmaStlAllocator<StackItem> > m_Stack;
  3414. bool m_InsideString;
  3415. void BeginValue(bool isString);
  3416. void WriteIndent(bool oneLess = false);
  3417. };
  3418. const char* const VmaJsonWriter::INDENT = " ";
  3419. VmaJsonWriter::VmaJsonWriter(const VkAllocationCallbacks* pAllocationCallbacks, VmaStringBuilder& sb) :
  3420. m_SB(sb),
  3421. m_Stack(VmaStlAllocator<StackItem>(pAllocationCallbacks)),
  3422. m_InsideString(false)
  3423. {
  3424. }
  3425. VmaJsonWriter::~VmaJsonWriter()
  3426. {
  3427. VMA_ASSERT(!m_InsideString);
  3428. VMA_ASSERT(m_Stack.empty());
  3429. }
  3430. void VmaJsonWriter::BeginObject(bool singleLine)
  3431. {
  3432. VMA_ASSERT(!m_InsideString);
  3433. BeginValue(false);
  3434. m_SB.Add('{');
  3435. StackItem item;
  3436. item.type = COLLECTION_TYPE_OBJECT;
  3437. item.valueCount = 0;
  3438. item.singleLineMode = singleLine;
  3439. m_Stack.push_back(item);
  3440. }
  3441. void VmaJsonWriter::EndObject()
  3442. {
  3443. VMA_ASSERT(!m_InsideString);
  3444. WriteIndent(true);
  3445. m_SB.Add('}');
  3446. VMA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_OBJECT);
  3447. m_Stack.pop_back();
  3448. }
  3449. void VmaJsonWriter::BeginArray(bool singleLine)
  3450. {
  3451. VMA_ASSERT(!m_InsideString);
  3452. BeginValue(false);
  3453. m_SB.Add('[');
  3454. StackItem item;
  3455. item.type = COLLECTION_TYPE_ARRAY;
  3456. item.valueCount = 0;
  3457. item.singleLineMode = singleLine;
  3458. m_Stack.push_back(item);
  3459. }
  3460. void VmaJsonWriter::EndArray()
  3461. {
  3462. VMA_ASSERT(!m_InsideString);
  3463. WriteIndent(true);
  3464. m_SB.Add(']');
  3465. VMA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_ARRAY);
  3466. m_Stack.pop_back();
  3467. }
  3468. void VmaJsonWriter::WriteString(const char* pStr)
  3469. {
  3470. BeginString(pStr);
  3471. EndString();
  3472. }
  3473. void VmaJsonWriter::BeginString(const char* pStr)
  3474. {
  3475. VMA_ASSERT(!m_InsideString);
  3476. BeginValue(true);
  3477. m_SB.Add('"');
  3478. m_InsideString = true;
  3479. if(pStr != VMA_NULL && pStr[0] != '\0')
  3480. {
  3481. ContinueString(pStr);
  3482. }
  3483. }
  3484. void VmaJsonWriter::ContinueString(const char* pStr)
  3485. {
  3486. VMA_ASSERT(m_InsideString);
  3487. const size_t strLen = strlen(pStr);
  3488. for(size_t i = 0; i < strLen; ++i)
  3489. {
  3490. char ch = pStr[i];
  3491. if(ch == '\'')
  3492. {
  3493. m_SB.Add("\\\\");
  3494. }
  3495. else if(ch == '"')
  3496. {
  3497. m_SB.Add("\\\"");
  3498. }
  3499. else if(ch >= 32)
  3500. {
  3501. m_SB.Add(ch);
  3502. }
  3503. else switch(ch)
  3504. {
  3505. case '\b':
  3506. m_SB.Add("\\b");
  3507. break;
  3508. case '\f':
  3509. m_SB.Add("\\f");
  3510. break;
  3511. case '\n':
  3512. m_SB.Add("\\n");
  3513. break;
  3514. case '\r':
  3515. m_SB.Add("\\r");
  3516. break;
  3517. case '\t':
  3518. m_SB.Add("\\t");
  3519. break;
  3520. default:
  3521. VMA_ASSERT(0 && "Character not currently supported.");
  3522. break;
  3523. }
  3524. }
  3525. }
  3526. void VmaJsonWriter::ContinueString(uint32_t n)
  3527. {
  3528. VMA_ASSERT(m_InsideString);
  3529. m_SB.AddNumber(n);
  3530. }
  3531. void VmaJsonWriter::ContinueString(uint64_t n)
  3532. {
  3533. VMA_ASSERT(m_InsideString);
  3534. m_SB.AddNumber(n);
  3535. }
  3536. void VmaJsonWriter::ContinueString_Pointer(const void* ptr)
  3537. {
  3538. VMA_ASSERT(m_InsideString);
  3539. m_SB.AddPointer(ptr);
  3540. }
  3541. void VmaJsonWriter::EndString(const char* pStr)
  3542. {
  3543. VMA_ASSERT(m_InsideString);
  3544. if(pStr != VMA_NULL && pStr[0] != '\0')
  3545. {
  3546. ContinueString(pStr);
  3547. }
  3548. m_SB.Add('"');
  3549. m_InsideString = false;
  3550. }
  3551. void VmaJsonWriter::WriteNumber(uint32_t n)
  3552. {
  3553. VMA_ASSERT(!m_InsideString);
  3554. BeginValue(false);
  3555. m_SB.AddNumber(n);
  3556. }
  3557. void VmaJsonWriter::WriteNumber(uint64_t n)
  3558. {
  3559. VMA_ASSERT(!m_InsideString);
  3560. BeginValue(false);
  3561. m_SB.AddNumber(n);
  3562. }
  3563. void VmaJsonWriter::WriteBool(bool b)
  3564. {
  3565. VMA_ASSERT(!m_InsideString);
  3566. BeginValue(false);
  3567. m_SB.Add(b ? "true" : "false");
  3568. }
  3569. void VmaJsonWriter::WriteNull()
  3570. {
  3571. VMA_ASSERT(!m_InsideString);
  3572. BeginValue(false);
  3573. m_SB.Add("null");
  3574. }
  3575. void VmaJsonWriter::BeginValue(bool isString)
  3576. {
  3577. if(!m_Stack.empty())
  3578. {
  3579. StackItem& currItem = m_Stack.back();
  3580. if(currItem.type == COLLECTION_TYPE_OBJECT &&
  3581. currItem.valueCount % 2 == 0)
  3582. {
  3583. VMA_ASSERT(isString);
  3584. }
  3585. if(currItem.type == COLLECTION_TYPE_OBJECT &&
  3586. currItem.valueCount % 2 != 0)
  3587. {
  3588. m_SB.Add(": ");
  3589. }
  3590. else if(currItem.valueCount > 0)
  3591. {
  3592. m_SB.Add(", ");
  3593. WriteIndent();
  3594. }
  3595. else
  3596. {
  3597. WriteIndent();
  3598. }
  3599. ++currItem.valueCount;
  3600. }
  3601. }
  3602. void VmaJsonWriter::WriteIndent(bool oneLess)
  3603. {
  3604. if(!m_Stack.empty() && !m_Stack.back().singleLineMode)
  3605. {
  3606. m_SB.AddNewLine();
  3607. size_t count = m_Stack.size();
  3608. if(count > 0 && oneLess)
  3609. {
  3610. --count;
  3611. }
  3612. for(size_t i = 0; i < count; ++i)
  3613. {
  3614. m_SB.Add(INDENT);
  3615. }
  3616. }
  3617. }
  3618. #endif // #if VMA_STATS_STRING_ENABLED
  3619. ////////////////////////////////////////////////////////////////////////////////
  3620. void VmaAllocation_T::SetUserData(VmaAllocator hAllocator, void* pUserData)
  3621. {
  3622. if(IsUserDataString())
  3623. {
  3624. VMA_ASSERT(pUserData == VMA_NULL || pUserData != m_pUserData);
  3625. FreeUserDataString(hAllocator);
  3626. if(pUserData != VMA_NULL)
  3627. {
  3628. const char* const newStrSrc = (char*)pUserData;
  3629. const size_t newStrLen = strlen(newStrSrc);
  3630. char* const newStrDst = vma_new_array(hAllocator, char, newStrLen + 1);
  3631. memcpy(newStrDst, newStrSrc, newStrLen + 1);
  3632. m_pUserData = newStrDst;
  3633. }
  3634. }
  3635. else
  3636. {
  3637. m_pUserData = pUserData;
  3638. }
  3639. }
  3640. VkDeviceSize VmaAllocation_T::GetOffset() const
  3641. {
  3642. switch(m_Type)
  3643. {
  3644. case ALLOCATION_TYPE_BLOCK:
  3645. return m_BlockAllocation.m_Offset;
  3646. case ALLOCATION_TYPE_DEDICATED:
  3647. return 0;
  3648. default:
  3649. VMA_ASSERT(0);
  3650. return 0;
  3651. }
  3652. }
  3653. VkDeviceMemory VmaAllocation_T::GetMemory() const
  3654. {
  3655. switch(m_Type)
  3656. {
  3657. case ALLOCATION_TYPE_BLOCK:
  3658. return m_BlockAllocation.m_Block->m_hMemory;
  3659. case ALLOCATION_TYPE_DEDICATED:
  3660. return m_DedicatedAllocation.m_hMemory;
  3661. default:
  3662. VMA_ASSERT(0);
  3663. return VK_NULL_HANDLE;
  3664. }
  3665. }
  3666. uint32_t VmaAllocation_T::GetMemoryTypeIndex() const
  3667. {
  3668. switch(m_Type)
  3669. {
  3670. case ALLOCATION_TYPE_BLOCK:
  3671. return m_BlockAllocation.m_Block->m_MemoryTypeIndex;
  3672. case ALLOCATION_TYPE_DEDICATED:
  3673. return m_DedicatedAllocation.m_MemoryTypeIndex;
  3674. default:
  3675. VMA_ASSERT(0);
  3676. return UINT32_MAX;
  3677. }
  3678. }
  3679. void* VmaAllocation_T::GetMappedData() const
  3680. {
  3681. switch(m_Type)
  3682. {
  3683. case ALLOCATION_TYPE_BLOCK:
  3684. if(m_MapCount != 0)
  3685. {
  3686. void* pBlockData = m_BlockAllocation.m_Block->m_Mapping.GetMappedData();
  3687. VMA_ASSERT(pBlockData != VMA_NULL);
  3688. return (char*)pBlockData + m_BlockAllocation.m_Offset;
  3689. }
  3690. else
  3691. {
  3692. return VMA_NULL;
  3693. }
  3694. break;
  3695. case ALLOCATION_TYPE_DEDICATED:
  3696. VMA_ASSERT((m_DedicatedAllocation.m_pMappedData != VMA_NULL) == (m_MapCount != 0));
  3697. return m_DedicatedAllocation.m_pMappedData;
  3698. default:
  3699. VMA_ASSERT(0);
  3700. return VMA_NULL;
  3701. }
  3702. }
  3703. bool VmaAllocation_T::CanBecomeLost() const
  3704. {
  3705. switch(m_Type)
  3706. {
  3707. case ALLOCATION_TYPE_BLOCK:
  3708. return m_BlockAllocation.m_CanBecomeLost;
  3709. case ALLOCATION_TYPE_DEDICATED:
  3710. return false;
  3711. default:
  3712. VMA_ASSERT(0);
  3713. return false;
  3714. }
  3715. }
  3716. VmaPool VmaAllocation_T::GetPool() const
  3717. {
  3718. VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK);
  3719. return m_BlockAllocation.m_hPool;
  3720. }
  3721. bool VmaAllocation_T::MakeLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)
  3722. {
  3723. VMA_ASSERT(CanBecomeLost());
  3724. /*
  3725. Warning: This is a carefully designed algorithm.
  3726. Do not modify unless you really know what you're doing :)
  3727. */
  3728. uint32_t localLastUseFrameIndex = GetLastUseFrameIndex();
  3729. for(;;)
  3730. {
  3731. if(localLastUseFrameIndex == VMA_FRAME_INDEX_LOST)
  3732. {
  3733. VMA_ASSERT(0);
  3734. return false;
  3735. }
  3736. else if(localLastUseFrameIndex + frameInUseCount >= currentFrameIndex)
  3737. {
  3738. return false;
  3739. }
  3740. else // Last use time earlier than current time.
  3741. {
  3742. if(CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, VMA_FRAME_INDEX_LOST))
  3743. {
  3744. // Setting hAllocation.LastUseFrameIndex atomic to VMA_FRAME_INDEX_LOST is enough to mark it as LOST.
  3745. // Calling code just needs to unregister this allocation in owning VmaDeviceMemoryBlock.
  3746. return true;
  3747. }
  3748. }
  3749. }
  3750. }
  3751. void VmaAllocation_T::FreeUserDataString(VmaAllocator hAllocator)
  3752. {
  3753. VMA_ASSERT(IsUserDataString());
  3754. if(m_pUserData != VMA_NULL)
  3755. {
  3756. char* const oldStr = (char*)m_pUserData;
  3757. const size_t oldStrLen = strlen(oldStr);
  3758. vma_delete_array(hAllocator, oldStr, oldStrLen + 1);
  3759. m_pUserData = VMA_NULL;
  3760. }
  3761. }
  3762. void VmaAllocation_T::BlockAllocMap()
  3763. {
  3764. VMA_ASSERT(GetType() == ALLOCATION_TYPE_BLOCK);
  3765. if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) < 0x7F)
  3766. {
  3767. ++m_MapCount;
  3768. }
  3769. else
  3770. {
  3771. VMA_ASSERT(0 && "Allocation mapped too many times simultaneously.");
  3772. }
  3773. }
  3774. void VmaAllocation_T::BlockAllocUnmap()
  3775. {
  3776. VMA_ASSERT(GetType() == ALLOCATION_TYPE_BLOCK);
  3777. if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) != 0)
  3778. {
  3779. --m_MapCount;
  3780. }
  3781. else
  3782. {
  3783. VMA_ASSERT(0 && "Unmapping allocation not previously mapped.");
  3784. }
  3785. }
  3786. VkResult VmaAllocation_T::DedicatedAllocMap(VmaAllocator hAllocator, void** ppData)
  3787. {
  3788. VMA_ASSERT(GetType() == ALLOCATION_TYPE_DEDICATED);
  3789. if(m_MapCount != 0)
  3790. {
  3791. if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) < 0x7F)
  3792. {
  3793. VMA_ASSERT(m_DedicatedAllocation.m_pMappedData != VMA_NULL);
  3794. *ppData = m_DedicatedAllocation.m_pMappedData;
  3795. ++m_MapCount;
  3796. return VK_SUCCESS;
  3797. }
  3798. else
  3799. {
  3800. VMA_ASSERT(0 && "Dedicated allocation mapped too many times simultaneously.");
  3801. return VK_ERROR_MEMORY_MAP_FAILED;
  3802. }
  3803. }
  3804. else
  3805. {
  3806. VkResult result = (*hAllocator->GetVulkanFunctions().vkMapMemory)(
  3807. hAllocator->m_hDevice,
  3808. m_DedicatedAllocation.m_hMemory,
  3809. 0, // offset
  3810. VK_WHOLE_SIZE,
  3811. 0, // flags
  3812. ppData);
  3813. if(result == VK_SUCCESS)
  3814. {
  3815. m_DedicatedAllocation.m_pMappedData = *ppData;
  3816. m_MapCount = 1;
  3817. }
  3818. return result;
  3819. }
  3820. }
  3821. void VmaAllocation_T::DedicatedAllocUnmap(VmaAllocator hAllocator)
  3822. {
  3823. VMA_ASSERT(GetType() == ALLOCATION_TYPE_DEDICATED);
  3824. if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) != 0)
  3825. {
  3826. --m_MapCount;
  3827. if(m_MapCount == 0)
  3828. {
  3829. m_DedicatedAllocation.m_pMappedData = VMA_NULL;
  3830. (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(
  3831. hAllocator->m_hDevice,
  3832. m_DedicatedAllocation.m_hMemory);
  3833. }
  3834. }
  3835. else
  3836. {
  3837. VMA_ASSERT(0 && "Unmapping dedicated allocation not previously mapped.");
  3838. }
  3839. }
  3840. #if VMA_STATS_STRING_ENABLED
  3841. // Correspond to values of enum VmaSuballocationType.
  3842. static const char* VMA_SUBALLOCATION_TYPE_NAMES[] = {
  3843. "FREE",
  3844. "UNKNOWN",
  3845. "BUFFER",
  3846. "IMAGE_UNKNOWN",
  3847. "IMAGE_LINEAR",
  3848. "IMAGE_OPTIMAL",
  3849. };
  3850. static void VmaPrintStatInfo(VmaJsonWriter& json, const VmaStatInfo& stat)
  3851. {
  3852. json.BeginObject();
  3853. json.WriteString("Blocks");
  3854. json.WriteNumber(stat.blockCount);
  3855. json.WriteString("Allocations");
  3856. json.WriteNumber(stat.allocationCount);
  3857. json.WriteString("UnusedRanges");
  3858. json.WriteNumber(stat.unusedRangeCount);
  3859. json.WriteString("UsedBytes");
  3860. json.WriteNumber(stat.usedBytes);
  3861. json.WriteString("UnusedBytes");
  3862. json.WriteNumber(stat.unusedBytes);
  3863. if(stat.allocationCount > 1)
  3864. {
  3865. json.WriteString("AllocationSize");
  3866. json.BeginObject(true);
  3867. json.WriteString("Min");
  3868. json.WriteNumber(stat.allocationSizeMin);
  3869. json.WriteString("Avg");
  3870. json.WriteNumber(stat.allocationSizeAvg);
  3871. json.WriteString("Max");
  3872. json.WriteNumber(stat.allocationSizeMax);
  3873. json.EndObject();
  3874. }
  3875. if(stat.unusedRangeCount > 1)
  3876. {
  3877. json.WriteString("UnusedRangeSize");
  3878. json.BeginObject(true);
  3879. json.WriteString("Min");
  3880. json.WriteNumber(stat.unusedRangeSizeMin);
  3881. json.WriteString("Avg");
  3882. json.WriteNumber(stat.unusedRangeSizeAvg);
  3883. json.WriteString("Max");
  3884. json.WriteNumber(stat.unusedRangeSizeMax);
  3885. json.EndObject();
  3886. }
  3887. json.EndObject();
  3888. }
  3889. #endif // #if VMA_STATS_STRING_ENABLED
  3890. struct VmaSuballocationItemSizeLess
  3891. {
  3892. bool operator()(
  3893. const VmaSuballocationList::iterator lhs,
  3894. const VmaSuballocationList::iterator rhs) const
  3895. {
  3896. return lhs->size < rhs->size;
  3897. }
  3898. bool operator()(
  3899. const VmaSuballocationList::iterator lhs,
  3900. VkDeviceSize rhsSize) const
  3901. {
  3902. return lhs->size < rhsSize;
  3903. }
  3904. };
  3905. ////////////////////////////////////////////////////////////////////////////////
  3906. // class VmaBlockMetadata
  3907. VmaBlockMetadata::VmaBlockMetadata(VmaAllocator hAllocator) :
  3908. m_Size(0),
  3909. m_FreeCount(0),
  3910. m_SumFreeSize(0),
  3911. m_Suballocations(VmaStlAllocator<VmaSuballocation>(hAllocator->GetAllocationCallbacks())),
  3912. m_FreeSuballocationsBySize(VmaStlAllocator<VmaSuballocationList::iterator>(hAllocator->GetAllocationCallbacks()))
  3913. {
  3914. }
  3915. VmaBlockMetadata::~VmaBlockMetadata()
  3916. {
  3917. }
  3918. void VmaBlockMetadata::Init(VkDeviceSize size)
  3919. {
  3920. m_Size = size;
  3921. m_FreeCount = 1;
  3922. m_SumFreeSize = size;
  3923. VmaSuballocation suballoc = {};
  3924. suballoc.offset = 0;
  3925. suballoc.size = size;
  3926. suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
  3927. suballoc.hAllocation = VK_NULL_HANDLE;
  3928. m_Suballocations.push_back(suballoc);
  3929. VmaSuballocationList::iterator suballocItem = m_Suballocations.end();
  3930. --suballocItem;
  3931. m_FreeSuballocationsBySize.push_back(suballocItem);
  3932. }
  3933. bool VmaBlockMetadata::Validate() const
  3934. {
  3935. if(m_Suballocations.empty())
  3936. {
  3937. return false;
  3938. }
  3939. // Expected offset of new suballocation as calculates from previous ones.
  3940. VkDeviceSize calculatedOffset = 0;
  3941. // Expected number of free suballocations as calculated from traversing their list.
  3942. uint32_t calculatedFreeCount = 0;
  3943. // Expected sum size of free suballocations as calculated from traversing their list.
  3944. VkDeviceSize calculatedSumFreeSize = 0;
  3945. // Expected number of free suballocations that should be registered in
  3946. // m_FreeSuballocationsBySize calculated from traversing their list.
  3947. size_t freeSuballocationsToRegister = 0;
  3948. // True if previous visisted suballocation was free.
  3949. bool prevFree = false;
  3950. for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin();
  3951. suballocItem != m_Suballocations.cend();
  3952. ++suballocItem)
  3953. {
  3954. const VmaSuballocation& subAlloc = *suballocItem;
  3955. // Actual offset of this suballocation doesn't match expected one.
  3956. if(subAlloc.offset != calculatedOffset)
  3957. {
  3958. return false;
  3959. }
  3960. const bool currFree = (subAlloc.type == VMA_SUBALLOCATION_TYPE_FREE);
  3961. // Two adjacent free suballocations are invalid. They should be merged.
  3962. if(prevFree && currFree)
  3963. {
  3964. return false;
  3965. }
  3966. prevFree = currFree;
  3967. if(currFree != (subAlloc.hAllocation == VK_NULL_HANDLE))
  3968. {
  3969. return false;
  3970. }
  3971. if(currFree)
  3972. {
  3973. calculatedSumFreeSize += subAlloc.size;
  3974. ++calculatedFreeCount;
  3975. if(subAlloc.size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
  3976. {
  3977. ++freeSuballocationsToRegister;
  3978. }
  3979. }
  3980. calculatedOffset += subAlloc.size;
  3981. }
  3982. // Number of free suballocations registered in m_FreeSuballocationsBySize doesn't
  3983. // match expected one.
  3984. if(m_FreeSuballocationsBySize.size() != freeSuballocationsToRegister)
  3985. {
  3986. return false;
  3987. }
  3988. VkDeviceSize lastSize = 0;
  3989. for(size_t i = 0; i < m_FreeSuballocationsBySize.size(); ++i)
  3990. {
  3991. VmaSuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[i];
  3992. // Only free suballocations can be registered in m_FreeSuballocationsBySize.
  3993. if(suballocItem->type != VMA_SUBALLOCATION_TYPE_FREE)
  3994. {
  3995. return false;
  3996. }
  3997. // They must be sorted by size ascending.
  3998. if(suballocItem->size < lastSize)
  3999. {
  4000. return false;
  4001. }
  4002. lastSize = suballocItem->size;
  4003. }
  4004. // Check if totals match calculacted values.
  4005. return
  4006. ValidateFreeSuballocationList() &&
  4007. (calculatedOffset == m_Size) &&
  4008. (calculatedSumFreeSize == m_SumFreeSize) &&
  4009. (calculatedFreeCount == m_FreeCount);
  4010. }
  4011. VkDeviceSize VmaBlockMetadata::GetUnusedRangeSizeMax() const
  4012. {
  4013. if(!m_FreeSuballocationsBySize.empty())
  4014. {
  4015. return m_FreeSuballocationsBySize.back()->size;
  4016. }
  4017. else
  4018. {
  4019. return 0;
  4020. }
  4021. }
  4022. bool VmaBlockMetadata::IsEmpty() const
  4023. {
  4024. return (m_Suballocations.size() == 1) && (m_FreeCount == 1);
  4025. }
  4026. void VmaBlockMetadata::CalcAllocationStatInfo(VmaStatInfo& outInfo) const
  4027. {
  4028. outInfo.blockCount = 1;
  4029. const uint32_t rangeCount = (uint32_t)m_Suballocations.size();
  4030. outInfo.allocationCount = rangeCount - m_FreeCount;
  4031. outInfo.unusedRangeCount = m_FreeCount;
  4032. outInfo.unusedBytes = m_SumFreeSize;
  4033. outInfo.usedBytes = m_Size - outInfo.unusedBytes;
  4034. outInfo.allocationSizeMin = UINT64_MAX;
  4035. outInfo.allocationSizeMax = 0;
  4036. outInfo.unusedRangeSizeMin = UINT64_MAX;
  4037. outInfo.unusedRangeSizeMax = 0;
  4038. for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin();
  4039. suballocItem != m_Suballocations.cend();
  4040. ++suballocItem)
  4041. {
  4042. const VmaSuballocation& suballoc = *suballocItem;
  4043. if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
  4044. {
  4045. outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size);
  4046. outInfo.allocationSizeMax = VMA_MAX(outInfo.allocationSizeMax, suballoc.size);
  4047. }
  4048. else
  4049. {
  4050. outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, suballoc.size);
  4051. outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, suballoc.size);
  4052. }
  4053. }
  4054. }
  4055. void VmaBlockMetadata::AddPoolStats(VmaPoolStats& inoutStats) const
  4056. {
  4057. const uint32_t rangeCount = (uint32_t)m_Suballocations.size();
  4058. inoutStats.size += m_Size;
  4059. inoutStats.unusedSize += m_SumFreeSize;
  4060. inoutStats.allocationCount += rangeCount - m_FreeCount;
  4061. inoutStats.unusedRangeCount += m_FreeCount;
  4062. inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, GetUnusedRangeSizeMax());
  4063. }
  4064. #if VMA_STATS_STRING_ENABLED
  4065. void VmaBlockMetadata::PrintDetailedMap(class VmaJsonWriter& json) const
  4066. {
  4067. json.BeginObject();
  4068. json.WriteString("TotalBytes");
  4069. json.WriteNumber(m_Size);
  4070. json.WriteString("UnusedBytes");
  4071. json.WriteNumber(m_SumFreeSize);
  4072. json.WriteString("Allocations");
  4073. json.WriteNumber(m_Suballocations.size() - m_FreeCount);
  4074. json.WriteString("UnusedRanges");
  4075. json.WriteNumber(m_FreeCount);
  4076. json.WriteString("Suballocations");
  4077. json.BeginArray();
  4078. size_t i = 0;
  4079. for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin();
  4080. suballocItem != m_Suballocations.cend();
  4081. ++suballocItem, ++i)
  4082. {
  4083. json.BeginObject(true);
  4084. json.WriteString("Type");
  4085. json.WriteString(VMA_SUBALLOCATION_TYPE_NAMES[suballocItem->type]);
  4086. json.WriteString("Size");
  4087. json.WriteNumber(suballocItem->size);
  4088. json.WriteString("Offset");
  4089. json.WriteNumber(suballocItem->offset);
  4090. if(suballocItem->type != VMA_SUBALLOCATION_TYPE_FREE)
  4091. {
  4092. const void* pUserData = suballocItem->hAllocation->GetUserData();
  4093. if(pUserData != VMA_NULL)
  4094. {
  4095. json.WriteString("UserData");
  4096. if(suballocItem->hAllocation->IsUserDataString())
  4097. {
  4098. json.WriteString((const char*)pUserData);
  4099. }
  4100. else
  4101. {
  4102. json.BeginString();
  4103. json.ContinueString_Pointer(pUserData);
  4104. json.EndString();
  4105. }
  4106. }
  4107. }
  4108. json.EndObject();
  4109. }
  4110. json.EndArray();
  4111. json.EndObject();
  4112. }
  4113. #endif // #if VMA_STATS_STRING_ENABLED
  4114. /*
  4115. How many suitable free suballocations to analyze before choosing best one.
  4116. - Set to 1 to use First-Fit algorithm - first suitable free suballocation will
  4117. be chosen.
  4118. - Set to UINT32_MAX to use Best-Fit/Worst-Fit algorithm - all suitable free
  4119. suballocations will be analized and best one will be chosen.
  4120. - Any other value is also acceptable.
  4121. */
  4122. //static const uint32_t MAX_SUITABLE_SUBALLOCATIONS_TO_CHECK = 8;
  4123. void VmaBlockMetadata::CreateFirstAllocationRequest(VmaAllocationRequest* pAllocationRequest)
  4124. {
  4125. VMA_ASSERT(IsEmpty());
  4126. pAllocationRequest->offset = 0;
  4127. pAllocationRequest->sumFreeSize = m_SumFreeSize;
  4128. pAllocationRequest->sumItemSize = 0;
  4129. pAllocationRequest->item = m_Suballocations.begin();
  4130. pAllocationRequest->itemsToMakeLostCount = 0;
  4131. }
  4132. bool VmaBlockMetadata::CreateAllocationRequest(
  4133. uint32_t currentFrameIndex,
  4134. uint32_t frameInUseCount,
  4135. VkDeviceSize bufferImageGranularity,
  4136. VkDeviceSize allocSize,
  4137. VkDeviceSize allocAlignment,
  4138. VmaSuballocationType allocType,
  4139. bool canMakeOtherLost,
  4140. VmaAllocationRequest* pAllocationRequest)
  4141. {
  4142. VMA_ASSERT(allocSize > 0);
  4143. VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE);
  4144. VMA_ASSERT(pAllocationRequest != VMA_NULL);
  4145. VMA_HEAVY_ASSERT(Validate());
  4146. // There is not enough total free space in this block to fullfill the request: Early return.
  4147. if(canMakeOtherLost == false && m_SumFreeSize < allocSize)
  4148. {
  4149. return false;
  4150. }
  4151. // New algorithm, efficiently searching freeSuballocationsBySize.
  4152. const size_t freeSuballocCount = m_FreeSuballocationsBySize.size();
  4153. if(freeSuballocCount > 0)
  4154. {
  4155. if(VMA_BEST_FIT)
  4156. {
  4157. // Find first free suballocation with size not less than allocSize.
  4158. VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess(
  4159. m_FreeSuballocationsBySize.data(),
  4160. m_FreeSuballocationsBySize.data() + freeSuballocCount,
  4161. allocSize,
  4162. VmaSuballocationItemSizeLess());
  4163. size_t index = it - m_FreeSuballocationsBySize.data();
  4164. for(; index < freeSuballocCount; ++index)
  4165. {
  4166. if(CheckAllocation(
  4167. currentFrameIndex,
  4168. frameInUseCount,
  4169. bufferImageGranularity,
  4170. allocSize,
  4171. allocAlignment,
  4172. allocType,
  4173. m_FreeSuballocationsBySize[index],
  4174. false, // canMakeOtherLost
  4175. &pAllocationRequest->offset,
  4176. &pAllocationRequest->itemsToMakeLostCount,
  4177. &pAllocationRequest->sumFreeSize,
  4178. &pAllocationRequest->sumItemSize))
  4179. {
  4180. pAllocationRequest->item = m_FreeSuballocationsBySize[index];
  4181. return true;
  4182. }
  4183. }
  4184. }
  4185. else
  4186. {
  4187. // Search staring from biggest suballocations.
  4188. for(size_t index = freeSuballocCount; index--; )
  4189. {
  4190. if(CheckAllocation(
  4191. currentFrameIndex,
  4192. frameInUseCount,
  4193. bufferImageGranularity,
  4194. allocSize,
  4195. allocAlignment,
  4196. allocType,
  4197. m_FreeSuballocationsBySize[index],
  4198. false, // canMakeOtherLost
  4199. &pAllocationRequest->offset,
  4200. &pAllocationRequest->itemsToMakeLostCount,
  4201. &pAllocationRequest->sumFreeSize,
  4202. &pAllocationRequest->sumItemSize))
  4203. {
  4204. pAllocationRequest->item = m_FreeSuballocationsBySize[index];
  4205. return true;
  4206. }
  4207. }
  4208. }
  4209. }
  4210. if(canMakeOtherLost)
  4211. {
  4212. // Brute-force algorithm. TODO: Come up with something better.
  4213. pAllocationRequest->sumFreeSize = VK_WHOLE_SIZE;
  4214. pAllocationRequest->sumItemSize = VK_WHOLE_SIZE;
  4215. VmaAllocationRequest tmpAllocRequest = {};
  4216. for(VmaSuballocationList::iterator suballocIt = m_Suballocations.begin();
  4217. suballocIt != m_Suballocations.end();
  4218. ++suballocIt)
  4219. {
  4220. if(suballocIt->type == VMA_SUBALLOCATION_TYPE_FREE ||
  4221. suballocIt->hAllocation->CanBecomeLost())
  4222. {
  4223. if(CheckAllocation(
  4224. currentFrameIndex,
  4225. frameInUseCount,
  4226. bufferImageGranularity,
  4227. allocSize,
  4228. allocAlignment,
  4229. allocType,
  4230. suballocIt,
  4231. canMakeOtherLost,
  4232. &tmpAllocRequest.offset,
  4233. &tmpAllocRequest.itemsToMakeLostCount,
  4234. &tmpAllocRequest.sumFreeSize,
  4235. &tmpAllocRequest.sumItemSize))
  4236. {
  4237. tmpAllocRequest.item = suballocIt;
  4238. if(tmpAllocRequest.CalcCost() < pAllocationRequest->CalcCost())
  4239. {
  4240. *pAllocationRequest = tmpAllocRequest;
  4241. }
  4242. }
  4243. }
  4244. }
  4245. if(pAllocationRequest->sumItemSize != VK_WHOLE_SIZE)
  4246. {
  4247. return true;
  4248. }
  4249. }
  4250. return false;
  4251. }
  4252. bool VmaBlockMetadata::MakeRequestedAllocationsLost(
  4253. uint32_t currentFrameIndex,
  4254. uint32_t frameInUseCount,
  4255. VmaAllocationRequest* pAllocationRequest)
  4256. {
  4257. while(pAllocationRequest->itemsToMakeLostCount > 0)
  4258. {
  4259. if(pAllocationRequest->item->type == VMA_SUBALLOCATION_TYPE_FREE)
  4260. {
  4261. ++pAllocationRequest->item;
  4262. }
  4263. VMA_ASSERT(pAllocationRequest->item != m_Suballocations.end());
  4264. VMA_ASSERT(pAllocationRequest->item->hAllocation != VK_NULL_HANDLE);
  4265. VMA_ASSERT(pAllocationRequest->item->hAllocation->CanBecomeLost());
  4266. if(pAllocationRequest->item->hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
  4267. {
  4268. pAllocationRequest->item = FreeSuballocation(pAllocationRequest->item);
  4269. --pAllocationRequest->itemsToMakeLostCount;
  4270. }
  4271. else
  4272. {
  4273. return false;
  4274. }
  4275. }
  4276. VMA_HEAVY_ASSERT(Validate());
  4277. VMA_ASSERT(pAllocationRequest->item != m_Suballocations.end());
  4278. VMA_ASSERT(pAllocationRequest->item->type == VMA_SUBALLOCATION_TYPE_FREE);
  4279. return true;
  4280. }
  4281. uint32_t VmaBlockMetadata::MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)
  4282. {
  4283. uint32_t lostAllocationCount = 0;
  4284. for(VmaSuballocationList::iterator it = m_Suballocations.begin();
  4285. it != m_Suballocations.end();
  4286. ++it)
  4287. {
  4288. if(it->type != VMA_SUBALLOCATION_TYPE_FREE &&
  4289. it->hAllocation->CanBecomeLost() &&
  4290. it->hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
  4291. {
  4292. it = FreeSuballocation(it);
  4293. ++lostAllocationCount;
  4294. }
  4295. }
  4296. return lostAllocationCount;
  4297. }
  4298. void VmaBlockMetadata::Alloc(
  4299. const VmaAllocationRequest& request,
  4300. VmaSuballocationType type,
  4301. VkDeviceSize allocSize,
  4302. VmaAllocation hAllocation)
  4303. {
  4304. VMA_ASSERT(request.item != m_Suballocations.end());
  4305. VmaSuballocation& suballoc = *request.item;
  4306. // Given suballocation is a free block.
  4307. VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
  4308. // Given offset is inside this suballocation.
  4309. VMA_ASSERT(request.offset >= suballoc.offset);
  4310. const VkDeviceSize paddingBegin = request.offset - suballoc.offset;
  4311. VMA_ASSERT(suballoc.size >= paddingBegin + allocSize);
  4312. const VkDeviceSize paddingEnd = suballoc.size - paddingBegin - allocSize;
  4313. // Unregister this free suballocation from m_FreeSuballocationsBySize and update
  4314. // it to become used.
  4315. UnregisterFreeSuballocation(request.item);
  4316. suballoc.offset = request.offset;
  4317. suballoc.size = allocSize;
  4318. suballoc.type = type;
  4319. suballoc.hAllocation = hAllocation;
  4320. // If there are any free bytes remaining at the end, insert new free suballocation after current one.
  4321. if(paddingEnd)
  4322. {
  4323. VmaSuballocation paddingSuballoc = {};
  4324. paddingSuballoc.offset = request.offset + allocSize;
  4325. paddingSuballoc.size = paddingEnd;
  4326. paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
  4327. VmaSuballocationList::iterator next = request.item;
  4328. ++next;
  4329. const VmaSuballocationList::iterator paddingEndItem =
  4330. m_Suballocations.insert(next, paddingSuballoc);
  4331. RegisterFreeSuballocation(paddingEndItem);
  4332. }
  4333. // If there are any free bytes remaining at the beginning, insert new free suballocation before current one.
  4334. if(paddingBegin)
  4335. {
  4336. VmaSuballocation paddingSuballoc = {};
  4337. paddingSuballoc.offset = request.offset - paddingBegin;
  4338. paddingSuballoc.size = paddingBegin;
  4339. paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
  4340. const VmaSuballocationList::iterator paddingBeginItem =
  4341. m_Suballocations.insert(request.item, paddingSuballoc);
  4342. RegisterFreeSuballocation(paddingBeginItem);
  4343. }
  4344. // Update totals.
  4345. m_FreeCount = m_FreeCount - 1;
  4346. if(paddingBegin > 0)
  4347. {
  4348. ++m_FreeCount;
  4349. }
  4350. if(paddingEnd > 0)
  4351. {
  4352. ++m_FreeCount;
  4353. }
  4354. m_SumFreeSize -= allocSize;
  4355. }
  4356. void VmaBlockMetadata::Free(const VmaAllocation allocation)
  4357. {
  4358. for(VmaSuballocationList::iterator suballocItem = m_Suballocations.begin();
  4359. suballocItem != m_Suballocations.end();
  4360. ++suballocItem)
  4361. {
  4362. VmaSuballocation& suballoc = *suballocItem;
  4363. if(suballoc.hAllocation == allocation)
  4364. {
  4365. FreeSuballocation(suballocItem);
  4366. VMA_HEAVY_ASSERT(Validate());
  4367. return;
  4368. }
  4369. }
  4370. VMA_ASSERT(0 && "Not found!");
  4371. }
  4372. bool VmaBlockMetadata::ValidateFreeSuballocationList() const
  4373. {
  4374. VkDeviceSize lastSize = 0;
  4375. for(size_t i = 0, count = m_FreeSuballocationsBySize.size(); i < count; ++i)
  4376. {
  4377. const VmaSuballocationList::iterator it = m_FreeSuballocationsBySize[i];
  4378. if(it->type != VMA_SUBALLOCATION_TYPE_FREE)
  4379. {
  4380. VMA_ASSERT(0);
  4381. return false;
  4382. }
  4383. if(it->size < VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
  4384. {
  4385. VMA_ASSERT(0);
  4386. return false;
  4387. }
  4388. if(it->size < lastSize)
  4389. {
  4390. VMA_ASSERT(0);
  4391. return false;
  4392. }
  4393. lastSize = it->size;
  4394. }
  4395. return true;
  4396. }
  4397. bool VmaBlockMetadata::CheckAllocation(
  4398. uint32_t currentFrameIndex,
  4399. uint32_t frameInUseCount,
  4400. VkDeviceSize bufferImageGranularity,
  4401. VkDeviceSize allocSize,
  4402. VkDeviceSize allocAlignment,
  4403. VmaSuballocationType allocType,
  4404. VmaSuballocationList::const_iterator suballocItem,
  4405. bool canMakeOtherLost,
  4406. VkDeviceSize* pOffset,
  4407. size_t* itemsToMakeLostCount,
  4408. VkDeviceSize* pSumFreeSize,
  4409. VkDeviceSize* pSumItemSize) const
  4410. {
  4411. VMA_ASSERT(allocSize > 0);
  4412. VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE);
  4413. VMA_ASSERT(suballocItem != m_Suballocations.cend());
  4414. VMA_ASSERT(pOffset != VMA_NULL);
  4415. *itemsToMakeLostCount = 0;
  4416. *pSumFreeSize = 0;
  4417. *pSumItemSize = 0;
  4418. if(canMakeOtherLost)
  4419. {
  4420. if(suballocItem->type == VMA_SUBALLOCATION_TYPE_FREE)
  4421. {
  4422. *pSumFreeSize = suballocItem->size;
  4423. }
  4424. else
  4425. {
  4426. if(suballocItem->hAllocation->CanBecomeLost() &&
  4427. suballocItem->hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
  4428. {
  4429. ++*itemsToMakeLostCount;
  4430. *pSumItemSize = suballocItem->size;
  4431. }
  4432. else
  4433. {
  4434. return false;
  4435. }
  4436. }
  4437. // Remaining size is too small for this request: Early return.
  4438. if(m_Size - suballocItem->offset < allocSize)
  4439. {
  4440. return false;
  4441. }
  4442. // Start from offset equal to beginning of this suballocation.
  4443. *pOffset = suballocItem->offset;
  4444. // Apply VMA_DEBUG_MARGIN at the beginning.
  4445. if((VMA_DEBUG_MARGIN > 0) && suballocItem != m_Suballocations.cbegin())
  4446. {
  4447. *pOffset += VMA_DEBUG_MARGIN;
  4448. }
  4449. // Apply alignment.
  4450. const VkDeviceSize alignment = VMA_MAX(allocAlignment, static_cast<VkDeviceSize>(VMA_DEBUG_ALIGNMENT));
  4451. *pOffset = VmaAlignUp(*pOffset, alignment);
  4452. // Check previous suballocations for BufferImageGranularity conflicts.
  4453. // Make bigger alignment if necessary.
  4454. if(bufferImageGranularity > 1)
  4455. {
  4456. bool bufferImageGranularityConflict = false;
  4457. VmaSuballocationList::const_iterator prevSuballocItem = suballocItem;
  4458. while(prevSuballocItem != m_Suballocations.cbegin())
  4459. {
  4460. --prevSuballocItem;
  4461. const VmaSuballocation& prevSuballoc = *prevSuballocItem;
  4462. if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, *pOffset, bufferImageGranularity))
  4463. {
  4464. if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType))
  4465. {
  4466. bufferImageGranularityConflict = true;
  4467. break;
  4468. }
  4469. }
  4470. else
  4471. // Already on previous page.
  4472. break;
  4473. }
  4474. if(bufferImageGranularityConflict)
  4475. {
  4476. *pOffset = VmaAlignUp(*pOffset, bufferImageGranularity);
  4477. }
  4478. }
  4479. // Now that we have final *pOffset, check if we are past suballocItem.
  4480. // If yes, return false - this function should be called for another suballocItem as starting point.
  4481. if(*pOffset >= suballocItem->offset + suballocItem->size)
  4482. {
  4483. return false;
  4484. }
  4485. // Calculate padding at the beginning based on current offset.
  4486. const VkDeviceSize paddingBegin = *pOffset - suballocItem->offset;
  4487. // Calculate required margin at the end if this is not last suballocation.
  4488. VmaSuballocationList::const_iterator next = suballocItem;
  4489. ++next;
  4490. const VkDeviceSize requiredEndMargin =
  4491. (next != m_Suballocations.cend()) ? VMA_DEBUG_MARGIN : 0;
  4492. const VkDeviceSize totalSize = paddingBegin + allocSize + requiredEndMargin;
  4493. // Another early return check.
  4494. if(suballocItem->offset + totalSize > m_Size)
  4495. {
  4496. return false;
  4497. }
  4498. // Advance lastSuballocItem until desired size is reached.
  4499. // Update itemsToMakeLostCount.
  4500. VmaSuballocationList::const_iterator lastSuballocItem = suballocItem;
  4501. if(totalSize > suballocItem->size)
  4502. {
  4503. VkDeviceSize remainingSize = totalSize - suballocItem->size;
  4504. while(remainingSize > 0)
  4505. {
  4506. ++lastSuballocItem;
  4507. if(lastSuballocItem == m_Suballocations.cend())
  4508. {
  4509. return false;
  4510. }
  4511. if(lastSuballocItem->type == VMA_SUBALLOCATION_TYPE_FREE)
  4512. {
  4513. *pSumFreeSize += lastSuballocItem->size;
  4514. }
  4515. else
  4516. {
  4517. VMA_ASSERT(lastSuballocItem->hAllocation != VK_NULL_HANDLE);
  4518. if(lastSuballocItem->hAllocation->CanBecomeLost() &&
  4519. lastSuballocItem->hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
  4520. {
  4521. ++*itemsToMakeLostCount;
  4522. *pSumItemSize += lastSuballocItem->size;
  4523. }
  4524. else
  4525. {
  4526. return false;
  4527. }
  4528. }
  4529. remainingSize = (lastSuballocItem->size < remainingSize) ?
  4530. remainingSize - lastSuballocItem->size : 0;
  4531. }
  4532. }
  4533. // Check next suballocations for BufferImageGranularity conflicts.
  4534. // If conflict exists, we must mark more allocations lost or fail.
  4535. if(bufferImageGranularity > 1)
  4536. {
  4537. VmaSuballocationList::const_iterator nextSuballocItem = lastSuballocItem;
  4538. ++nextSuballocItem;
  4539. while(nextSuballocItem != m_Suballocations.cend())
  4540. {
  4541. const VmaSuballocation& nextSuballoc = *nextSuballocItem;
  4542. if(VmaBlocksOnSamePage(*pOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
  4543. {
  4544. if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type))
  4545. {
  4546. VMA_ASSERT(nextSuballoc.hAllocation != VK_NULL_HANDLE);
  4547. if(nextSuballoc.hAllocation->CanBecomeLost() &&
  4548. nextSuballoc.hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
  4549. {
  4550. ++*itemsToMakeLostCount;
  4551. }
  4552. else
  4553. {
  4554. return false;
  4555. }
  4556. }
  4557. }
  4558. else
  4559. {
  4560. // Already on next page.
  4561. break;
  4562. }
  4563. ++nextSuballocItem;
  4564. }
  4565. }
  4566. }
  4567. else
  4568. {
  4569. const VmaSuballocation& suballoc = *suballocItem;
  4570. VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
  4571. *pSumFreeSize = suballoc.size;
  4572. // Size of this suballocation is too small for this request: Early return.
  4573. if(suballoc.size < allocSize)
  4574. {
  4575. return false;
  4576. }
  4577. // Start from offset equal to beginning of this suballocation.
  4578. *pOffset = suballoc.offset;
  4579. // Apply VMA_DEBUG_MARGIN at the beginning.
  4580. if((VMA_DEBUG_MARGIN > 0) && suballocItem != m_Suballocations.cbegin())
  4581. {
  4582. *pOffset += VMA_DEBUG_MARGIN;
  4583. }
  4584. // Apply alignment.
  4585. const VkDeviceSize alignment = VMA_MAX(allocAlignment, static_cast<VkDeviceSize>(VMA_DEBUG_ALIGNMENT));
  4586. *pOffset = VmaAlignUp(*pOffset, alignment);
  4587. // Check previous suballocations for BufferImageGranularity conflicts.
  4588. // Make bigger alignment if necessary.
  4589. if(bufferImageGranularity > 1)
  4590. {
  4591. bool bufferImageGranularityConflict = false;
  4592. VmaSuballocationList::const_iterator prevSuballocItem = suballocItem;
  4593. while(prevSuballocItem != m_Suballocations.cbegin())
  4594. {
  4595. --prevSuballocItem;
  4596. const VmaSuballocation& prevSuballoc = *prevSuballocItem;
  4597. if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, *pOffset, bufferImageGranularity))
  4598. {
  4599. if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType))
  4600. {
  4601. bufferImageGranularityConflict = true;
  4602. break;
  4603. }
  4604. }
  4605. else
  4606. // Already on previous page.
  4607. break;
  4608. }
  4609. if(bufferImageGranularityConflict)
  4610. {
  4611. *pOffset = VmaAlignUp(*pOffset, bufferImageGranularity);
  4612. }
  4613. }
  4614. // Calculate padding at the beginning based on current offset.
  4615. const VkDeviceSize paddingBegin = *pOffset - suballoc.offset;
  4616. // Calculate required margin at the end if this is not last suballocation.
  4617. VmaSuballocationList::const_iterator next = suballocItem;
  4618. ++next;
  4619. const VkDeviceSize requiredEndMargin =
  4620. (next != m_Suballocations.cend()) ? VMA_DEBUG_MARGIN : 0;
  4621. // Fail if requested size plus margin before and after is bigger than size of this suballocation.
  4622. if(paddingBegin + allocSize + requiredEndMargin > suballoc.size)
  4623. {
  4624. return false;
  4625. }
  4626. // Check next suballocations for BufferImageGranularity conflicts.
  4627. // If conflict exists, allocation cannot be made here.
  4628. if(bufferImageGranularity > 1)
  4629. {
  4630. VmaSuballocationList::const_iterator nextSuballocItem = suballocItem;
  4631. ++nextSuballocItem;
  4632. while(nextSuballocItem != m_Suballocations.cend())
  4633. {
  4634. const VmaSuballocation& nextSuballoc = *nextSuballocItem;
  4635. if(VmaBlocksOnSamePage(*pOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
  4636. {
  4637. if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type))
  4638. {
  4639. return false;
  4640. }
  4641. }
  4642. else
  4643. {
  4644. // Already on next page.
  4645. break;
  4646. }
  4647. ++nextSuballocItem;
  4648. }
  4649. }
  4650. }
  4651. // All tests passed: Success. pOffset is already filled.
  4652. return true;
  4653. }
  4654. void VmaBlockMetadata::MergeFreeWithNext(VmaSuballocationList::iterator item)
  4655. {
  4656. VMA_ASSERT(item != m_Suballocations.end());
  4657. VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
  4658. VmaSuballocationList::iterator nextItem = item;
  4659. ++nextItem;
  4660. VMA_ASSERT(nextItem != m_Suballocations.end());
  4661. VMA_ASSERT(nextItem->type == VMA_SUBALLOCATION_TYPE_FREE);
  4662. item->size += nextItem->size;
  4663. --m_FreeCount;
  4664. m_Suballocations.erase(nextItem);
  4665. }
  4666. VmaSuballocationList::iterator VmaBlockMetadata::FreeSuballocation(VmaSuballocationList::iterator suballocItem)
  4667. {
  4668. // Change this suballocation to be marked as free.
  4669. VmaSuballocation& suballoc = *suballocItem;
  4670. suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
  4671. suballoc.hAllocation = VK_NULL_HANDLE;
  4672. // Update totals.
  4673. ++m_FreeCount;
  4674. m_SumFreeSize += suballoc.size;
  4675. // Merge with previous and/or next suballocation if it's also free.
  4676. bool mergeWithNext = false;
  4677. bool mergeWithPrev = false;
  4678. VmaSuballocationList::iterator nextItem = suballocItem;
  4679. ++nextItem;
  4680. if((nextItem != m_Suballocations.end()) && (nextItem->type == VMA_SUBALLOCATION_TYPE_FREE))
  4681. {
  4682. mergeWithNext = true;
  4683. }
  4684. VmaSuballocationList::iterator prevItem = suballocItem;
  4685. if(suballocItem != m_Suballocations.begin())
  4686. {
  4687. --prevItem;
  4688. if(prevItem->type == VMA_SUBALLOCATION_TYPE_FREE)
  4689. {
  4690. mergeWithPrev = true;
  4691. }
  4692. }
  4693. if(mergeWithNext)
  4694. {
  4695. UnregisterFreeSuballocation(nextItem);
  4696. MergeFreeWithNext(suballocItem);
  4697. }
  4698. if(mergeWithPrev)
  4699. {
  4700. UnregisterFreeSuballocation(prevItem);
  4701. MergeFreeWithNext(prevItem);
  4702. RegisterFreeSuballocation(prevItem);
  4703. return prevItem;
  4704. }
  4705. else
  4706. {
  4707. RegisterFreeSuballocation(suballocItem);
  4708. return suballocItem;
  4709. }
  4710. }
  4711. void VmaBlockMetadata::RegisterFreeSuballocation(VmaSuballocationList::iterator item)
  4712. {
  4713. VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
  4714. VMA_ASSERT(item->size > 0);
  4715. // You may want to enable this validation at the beginning or at the end of
  4716. // this function, depending on what do you want to check.
  4717. VMA_HEAVY_ASSERT(ValidateFreeSuballocationList());
  4718. if(item->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
  4719. {
  4720. if(m_FreeSuballocationsBySize.empty())
  4721. {
  4722. m_FreeSuballocationsBySize.push_back(item);
  4723. }
  4724. else
  4725. {
  4726. VmaVectorInsertSorted<VmaSuballocationItemSizeLess>(m_FreeSuballocationsBySize, item);
  4727. }
  4728. }
  4729. //VMA_HEAVY_ASSERT(ValidateFreeSuballocationList());
  4730. }
  4731. void VmaBlockMetadata::UnregisterFreeSuballocation(VmaSuballocationList::iterator item)
  4732. {
  4733. VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
  4734. VMA_ASSERT(item->size > 0);
  4735. // You may want to enable this validation at the beginning or at the end of
  4736. // this function, depending on what do you want to check.
  4737. VMA_HEAVY_ASSERT(ValidateFreeSuballocationList());
  4738. if(item->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
  4739. {
  4740. VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess(
  4741. m_FreeSuballocationsBySize.data(),
  4742. m_FreeSuballocationsBySize.data() + m_FreeSuballocationsBySize.size(),
  4743. item,
  4744. VmaSuballocationItemSizeLess());
  4745. for(size_t index = it - m_FreeSuballocationsBySize.data();
  4746. index < m_FreeSuballocationsBySize.size();
  4747. ++index)
  4748. {
  4749. if(m_FreeSuballocationsBySize[index] == item)
  4750. {
  4751. VmaVectorRemove(m_FreeSuballocationsBySize, index);
  4752. return;
  4753. }
  4754. VMA_ASSERT((m_FreeSuballocationsBySize[index]->size == item->size) && "Not found.");
  4755. }
  4756. VMA_ASSERT(0 && "Not found.");
  4757. }
  4758. //VMA_HEAVY_ASSERT(ValidateFreeSuballocationList());
  4759. }
  4760. ////////////////////////////////////////////////////////////////////////////////
  4761. // class VmaDeviceMemoryMapping
  4762. VmaDeviceMemoryMapping::VmaDeviceMemoryMapping() :
  4763. m_MapCount(0),
  4764. m_pMappedData(VMA_NULL)
  4765. {
  4766. }
  4767. VmaDeviceMemoryMapping::~VmaDeviceMemoryMapping()
  4768. {
  4769. VMA_ASSERT(m_MapCount == 0 && "VkDeviceMemory block is being destroyed while it is still mapped.");
  4770. }
  4771. VkResult VmaDeviceMemoryMapping::Map(VmaAllocator hAllocator, VkDeviceMemory hMemory, void **ppData)
  4772. {
  4773. VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex);
  4774. if(m_MapCount != 0)
  4775. {
  4776. ++m_MapCount;
  4777. VMA_ASSERT(m_pMappedData != VMA_NULL);
  4778. if(ppData != VMA_NULL)
  4779. {
  4780. *ppData = m_pMappedData;
  4781. }
  4782. return VK_SUCCESS;
  4783. }
  4784. else
  4785. {
  4786. VkResult result = (*hAllocator->GetVulkanFunctions().vkMapMemory)(
  4787. hAllocator->m_hDevice,
  4788. hMemory,
  4789. 0, // offset
  4790. VK_WHOLE_SIZE,
  4791. 0, // flags
  4792. &m_pMappedData);
  4793. if(result == VK_SUCCESS)
  4794. {
  4795. if(ppData != VMA_NULL)
  4796. {
  4797. *ppData = m_pMappedData;
  4798. }
  4799. m_MapCount = 1;
  4800. }
  4801. return result;
  4802. }
  4803. }
  4804. void VmaDeviceMemoryMapping::Unmap(VmaAllocator hAllocator, VkDeviceMemory hMemory)
  4805. {
  4806. VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex);
  4807. if(m_MapCount != 0)
  4808. {
  4809. if(--m_MapCount == 0)
  4810. {
  4811. m_pMappedData = VMA_NULL;
  4812. (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(hAllocator->m_hDevice, hMemory);
  4813. }
  4814. }
  4815. else
  4816. {
  4817. VMA_ASSERT(0 && "VkDeviceMemory block is being unmapped while it was not previously mapped.");
  4818. }
  4819. }
  4820. ////////////////////////////////////////////////////////////////////////////////
  4821. // class VmaDeviceMemoryBlock
  4822. VmaDeviceMemoryBlock::VmaDeviceMemoryBlock(VmaAllocator hAllocator) :
  4823. m_MemoryTypeIndex(UINT32_MAX),
  4824. m_hMemory(VK_NULL_HANDLE),
  4825. m_Metadata(hAllocator)
  4826. {
  4827. }
  4828. void VmaDeviceMemoryBlock::Init(
  4829. uint32_t newMemoryTypeIndex,
  4830. VkDeviceMemory newMemory,
  4831. VkDeviceSize newSize)
  4832. {
  4833. VMA_ASSERT(m_hMemory == VK_NULL_HANDLE);
  4834. m_MemoryTypeIndex = newMemoryTypeIndex;
  4835. m_hMemory = newMemory;
  4836. m_Metadata.Init(newSize);
  4837. }
  4838. void VmaDeviceMemoryBlock::Destroy(VmaAllocator allocator)
  4839. {
  4840. // This is the most important assert in the entire library.
  4841. // Hitting it means you have some memory leak - unreleased VmaAllocation objects.
  4842. VMA_ASSERT(m_Metadata.IsEmpty() && "Some allocations were not freed before destruction of this memory block!");
  4843. VMA_ASSERT(m_hMemory != VK_NULL_HANDLE);
  4844. allocator->FreeVulkanMemory(m_MemoryTypeIndex, m_Metadata.GetSize(), m_hMemory);
  4845. m_hMemory = VK_NULL_HANDLE;
  4846. }
  4847. bool VmaDeviceMemoryBlock::Validate() const
  4848. {
  4849. if((m_hMemory == VK_NULL_HANDLE) ||
  4850. (m_Metadata.GetSize() == 0))
  4851. {
  4852. return false;
  4853. }
  4854. return m_Metadata.Validate();
  4855. }
  4856. VkResult VmaDeviceMemoryBlock::Map(VmaAllocator hAllocator, void** ppData)
  4857. {
  4858. return m_Mapping.Map(hAllocator, m_hMemory, ppData);
  4859. }
  4860. void VmaDeviceMemoryBlock::Unmap(VmaAllocator hAllocator)
  4861. {
  4862. m_Mapping.Unmap(hAllocator, m_hMemory);
  4863. }
  4864. static void InitStatInfo(VmaStatInfo& outInfo)
  4865. {
  4866. memset(&outInfo, 0, sizeof(outInfo));
  4867. outInfo.allocationSizeMin = UINT64_MAX;
  4868. outInfo.unusedRangeSizeMin = UINT64_MAX;
  4869. }
  4870. // Adds statistics srcInfo into inoutInfo, like: inoutInfo += srcInfo.
  4871. static void VmaAddStatInfo(VmaStatInfo& inoutInfo, const VmaStatInfo& srcInfo)
  4872. {
  4873. inoutInfo.blockCount += srcInfo.blockCount;
  4874. inoutInfo.allocationCount += srcInfo.allocationCount;
  4875. inoutInfo.unusedRangeCount += srcInfo.unusedRangeCount;
  4876. inoutInfo.usedBytes += srcInfo.usedBytes;
  4877. inoutInfo.unusedBytes += srcInfo.unusedBytes;
  4878. inoutInfo.allocationSizeMin = VMA_MIN(inoutInfo.allocationSizeMin, srcInfo.allocationSizeMin);
  4879. inoutInfo.allocationSizeMax = VMA_MAX(inoutInfo.allocationSizeMax, srcInfo.allocationSizeMax);
  4880. inoutInfo.unusedRangeSizeMin = VMA_MIN(inoutInfo.unusedRangeSizeMin, srcInfo.unusedRangeSizeMin);
  4881. inoutInfo.unusedRangeSizeMax = VMA_MAX(inoutInfo.unusedRangeSizeMax, srcInfo.unusedRangeSizeMax);
  4882. }
  4883. static void VmaPostprocessCalcStatInfo(VmaStatInfo& inoutInfo)
  4884. {
  4885. inoutInfo.allocationSizeAvg = (inoutInfo.allocationCount > 0) ?
  4886. VmaRoundDiv<VkDeviceSize>(inoutInfo.usedBytes, inoutInfo.allocationCount) : 0;
  4887. inoutInfo.unusedRangeSizeAvg = (inoutInfo.unusedRangeCount > 0) ?
  4888. VmaRoundDiv<VkDeviceSize>(inoutInfo.unusedBytes, inoutInfo.unusedRangeCount) : 0;
  4889. }
  4890. VmaPool_T::VmaPool_T(
  4891. VmaAllocator hAllocator,
  4892. const VmaPoolCreateInfo& createInfo) :
  4893. m_BlockVector(
  4894. hAllocator,
  4895. createInfo.memoryTypeIndex,
  4896. createInfo.blockSize,
  4897. createInfo.minBlockCount,
  4898. createInfo.maxBlockCount,
  4899. (createInfo.flags & VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT) != 0 ? 1 : hAllocator->GetBufferImageGranularity(),
  4900. createInfo.frameInUseCount,
  4901. true) // isCustomPool
  4902. {
  4903. }
  4904. VmaPool_T::~VmaPool_T()
  4905. {
  4906. }
  4907. #if VMA_STATS_STRING_ENABLED
  4908. #endif // #if VMA_STATS_STRING_ENABLED
  4909. VmaBlockVector::VmaBlockVector(
  4910. VmaAllocator hAllocator,
  4911. uint32_t memoryTypeIndex,
  4912. VkDeviceSize preferredBlockSize,
  4913. size_t minBlockCount,
  4914. size_t maxBlockCount,
  4915. VkDeviceSize bufferImageGranularity,
  4916. uint32_t frameInUseCount,
  4917. bool isCustomPool) :
  4918. m_hAllocator(hAllocator),
  4919. m_MemoryTypeIndex(memoryTypeIndex),
  4920. m_PreferredBlockSize(preferredBlockSize),
  4921. m_MinBlockCount(minBlockCount),
  4922. m_MaxBlockCount(maxBlockCount),
  4923. m_BufferImageGranularity(bufferImageGranularity),
  4924. m_FrameInUseCount(frameInUseCount),
  4925. m_IsCustomPool(isCustomPool),
  4926. m_Blocks(VmaStlAllocator<VmaDeviceMemoryBlock*>(hAllocator->GetAllocationCallbacks())),
  4927. m_HasEmptyBlock(false),
  4928. m_pDefragmentator(VMA_NULL)
  4929. {
  4930. }
  4931. VmaBlockVector::~VmaBlockVector()
  4932. {
  4933. VMA_ASSERT(m_pDefragmentator == VMA_NULL);
  4934. for(size_t i = m_Blocks.size(); i--; )
  4935. {
  4936. m_Blocks[i]->Destroy(m_hAllocator);
  4937. vma_delete(m_hAllocator, m_Blocks[i]);
  4938. }
  4939. }
  4940. VkResult VmaBlockVector::CreateMinBlocks()
  4941. {
  4942. for(size_t i = 0; i < m_MinBlockCount; ++i)
  4943. {
  4944. VkResult res = CreateBlock(m_PreferredBlockSize, VMA_NULL);
  4945. if(res != VK_SUCCESS)
  4946. {
  4947. return res;
  4948. }
  4949. }
  4950. return VK_SUCCESS;
  4951. }
  4952. void VmaBlockVector::GetPoolStats(VmaPoolStats* pStats)
  4953. {
  4954. pStats->size = 0;
  4955. pStats->unusedSize = 0;
  4956. pStats->allocationCount = 0;
  4957. pStats->unusedRangeCount = 0;
  4958. pStats->unusedRangeSizeMax = 0;
  4959. VmaMutexLock lock(m_Mutex, m_hAllocator->m_UseMutex);
  4960. for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
  4961. {
  4962. const VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex];
  4963. VMA_ASSERT(pBlock);
  4964. VMA_HEAVY_ASSERT(pBlock->Validate());
  4965. pBlock->m_Metadata.AddPoolStats(*pStats);
  4966. }
  4967. }
  4968. static const uint32_t VMA_ALLOCATION_TRY_COUNT = 32;
  4969. VkResult VmaBlockVector::Allocate(
  4970. VmaPool hCurrentPool,
  4971. uint32_t currentFrameIndex,
  4972. const VkMemoryRequirements& vkMemReq,
  4973. const VmaAllocationCreateInfo& createInfo,
  4974. VmaSuballocationType suballocType,
  4975. VmaAllocation* pAllocation)
  4976. {
  4977. const bool mapped = (createInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0;
  4978. const bool isUserDataString = (createInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0;
  4979. VmaMutexLock lock(m_Mutex, m_hAllocator->m_UseMutex);
  4980. // 1. Search existing allocations. Try to allocate without making other allocations lost.
  4981. // Forward order in m_Blocks - prefer blocks with smallest amount of free space.
  4982. for(size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex )
  4983. {
  4984. VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];
  4985. VMA_ASSERT(pCurrBlock);
  4986. VmaAllocationRequest currRequest = {};
  4987. if(pCurrBlock->m_Metadata.CreateAllocationRequest(
  4988. currentFrameIndex,
  4989. m_FrameInUseCount,
  4990. m_BufferImageGranularity,
  4991. vkMemReq.size,
  4992. vkMemReq.alignment,
  4993. suballocType,
  4994. false, // canMakeOtherLost
  4995. &currRequest))
  4996. {
  4997. // Allocate from pCurrBlock.
  4998. VMA_ASSERT(currRequest.itemsToMakeLostCount == 0);
  4999. if(mapped)
  5000. {
  5001. VkResult res = pCurrBlock->Map(m_hAllocator, nullptr);
  5002. if(res != VK_SUCCESS)
  5003. {
  5004. return res;
  5005. }
  5006. }
  5007. // We no longer have an empty Allocation.
  5008. if(pCurrBlock->m_Metadata.IsEmpty())
  5009. {
  5010. m_HasEmptyBlock = false;
  5011. }
  5012. *pAllocation = vma_new(m_hAllocator, VmaAllocation_T)(currentFrameIndex, isUserDataString);
  5013. pCurrBlock->m_Metadata.Alloc(currRequest, suballocType, vkMemReq.size, *pAllocation);
  5014. (*pAllocation)->InitBlockAllocation(
  5015. hCurrentPool,
  5016. pCurrBlock,
  5017. currRequest.offset,
  5018. vkMemReq.alignment,
  5019. vkMemReq.size,
  5020. suballocType,
  5021. mapped,
  5022. (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0);
  5023. VMA_HEAVY_ASSERT(pCurrBlock->Validate());
  5024. VMA_DEBUG_LOG(" Returned from existing allocation #%u", (uint32_t)blockIndex);
  5025. (*pAllocation)->SetUserData(m_hAllocator, createInfo.pUserData);
  5026. return VK_SUCCESS;
  5027. }
  5028. }
  5029. const bool canCreateNewBlock =
  5030. ((createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0) &&
  5031. (m_Blocks.size() < m_MaxBlockCount);
  5032. // 2. Try to create new block.
  5033. if(canCreateNewBlock)
  5034. {
  5035. // 2.1. Start with full preferredBlockSize.
  5036. VkDeviceSize blockSize = m_PreferredBlockSize;
  5037. size_t newBlockIndex = 0;
  5038. VkResult res = CreateBlock(blockSize, &newBlockIndex);
  5039. // Allocating blocks of other sizes is allowed only in default pools.
  5040. // In custom pools block size is fixed.
  5041. if(res < 0 && m_IsCustomPool == false)
  5042. {
  5043. // 2.2. Try half the size.
  5044. blockSize /= 2;
  5045. if(blockSize >= vkMemReq.size)
  5046. {
  5047. res = CreateBlock(blockSize, &newBlockIndex);
  5048. if(res < 0)
  5049. {
  5050. // 2.3. Try quarter the size.
  5051. blockSize /= 2;
  5052. if(blockSize >= vkMemReq.size)
  5053. {
  5054. res = CreateBlock(blockSize, &newBlockIndex);
  5055. }
  5056. }
  5057. }
  5058. }
  5059. if(res == VK_SUCCESS)
  5060. {
  5061. VmaDeviceMemoryBlock* const pBlock = m_Blocks[newBlockIndex];
  5062. VMA_ASSERT(pBlock->m_Metadata.GetSize() >= vkMemReq.size);
  5063. if(mapped)
  5064. {
  5065. res = pBlock->Map(m_hAllocator, nullptr);
  5066. if(res != VK_SUCCESS)
  5067. {
  5068. return res;
  5069. }
  5070. }
  5071. // Allocate from pBlock. Because it is empty, dstAllocRequest can be trivially filled.
  5072. VmaAllocationRequest allocRequest;
  5073. pBlock->m_Metadata.CreateFirstAllocationRequest(&allocRequest);
  5074. *pAllocation = vma_new(m_hAllocator, VmaAllocation_T)(currentFrameIndex, isUserDataString);
  5075. pBlock->m_Metadata.Alloc(allocRequest, suballocType, vkMemReq.size, *pAllocation);
  5076. (*pAllocation)->InitBlockAllocation(
  5077. hCurrentPool,
  5078. pBlock,
  5079. allocRequest.offset,
  5080. vkMemReq.alignment,
  5081. vkMemReq.size,
  5082. suballocType,
  5083. mapped,
  5084. (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0);
  5085. VMA_HEAVY_ASSERT(pBlock->Validate());
  5086. VMA_DEBUG_LOG(" Created new allocation Size=%llu", allocInfo.allocationSize);
  5087. (*pAllocation)->SetUserData(m_hAllocator, createInfo.pUserData);
  5088. return VK_SUCCESS;
  5089. }
  5090. }
  5091. const bool canMakeOtherLost = (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT) != 0;
  5092. // 3. Try to allocate from existing blocks with making other allocations lost.
  5093. if(canMakeOtherLost)
  5094. {
  5095. uint32_t tryIndex = 0;
  5096. for(; tryIndex < VMA_ALLOCATION_TRY_COUNT; ++tryIndex)
  5097. {
  5098. VmaDeviceMemoryBlock* pBestRequestBlock = VMA_NULL;
  5099. VmaAllocationRequest bestRequest = {};
  5100. VkDeviceSize bestRequestCost = VK_WHOLE_SIZE;
  5101. // 1. Search existing allocations.
  5102. // Forward order in m_Blocks - prefer blocks with smallest amount of free space.
  5103. for(size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex )
  5104. {
  5105. VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];
  5106. VMA_ASSERT(pCurrBlock);
  5107. VmaAllocationRequest currRequest = {};
  5108. if(pCurrBlock->m_Metadata.CreateAllocationRequest(
  5109. currentFrameIndex,
  5110. m_FrameInUseCount,
  5111. m_BufferImageGranularity,
  5112. vkMemReq.size,
  5113. vkMemReq.alignment,
  5114. suballocType,
  5115. canMakeOtherLost,
  5116. &currRequest))
  5117. {
  5118. const VkDeviceSize currRequestCost = currRequest.CalcCost();
  5119. if(pBestRequestBlock == VMA_NULL ||
  5120. currRequestCost < bestRequestCost)
  5121. {
  5122. pBestRequestBlock = pCurrBlock;
  5123. bestRequest = currRequest;
  5124. bestRequestCost = currRequestCost;
  5125. if(bestRequestCost == 0)
  5126. {
  5127. break;
  5128. }
  5129. }
  5130. }
  5131. }
  5132. if(pBestRequestBlock != VMA_NULL)
  5133. {
  5134. if(mapped)
  5135. {
  5136. VkResult res = pBestRequestBlock->Map(m_hAllocator, nullptr);
  5137. if(res != VK_SUCCESS)
  5138. {
  5139. return res;
  5140. }
  5141. }
  5142. if(pBestRequestBlock->m_Metadata.MakeRequestedAllocationsLost(
  5143. currentFrameIndex,
  5144. m_FrameInUseCount,
  5145. &bestRequest))
  5146. {
  5147. // We no longer have an empty Allocation.
  5148. if(pBestRequestBlock->m_Metadata.IsEmpty())
  5149. {
  5150. m_HasEmptyBlock = false;
  5151. }
  5152. // Allocate from this pBlock.
  5153. *pAllocation = vma_new(m_hAllocator, VmaAllocation_T)(currentFrameIndex, isUserDataString);
  5154. pBestRequestBlock->m_Metadata.Alloc(bestRequest, suballocType, vkMemReq.size, *pAllocation);
  5155. (*pAllocation)->InitBlockAllocation(
  5156. hCurrentPool,
  5157. pBestRequestBlock,
  5158. bestRequest.offset,
  5159. vkMemReq.alignment,
  5160. vkMemReq.size,
  5161. suballocType,
  5162. mapped,
  5163. (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0);
  5164. VMA_HEAVY_ASSERT(pBlock->Validate());
  5165. VMA_DEBUG_LOG(" Returned from existing allocation #%u", (uint32_t)blockIndex);
  5166. (*pAllocation)->SetUserData(m_hAllocator, createInfo.pUserData);
  5167. return VK_SUCCESS;
  5168. }
  5169. // else: Some allocations must have been touched while we are here. Next try.
  5170. }
  5171. else
  5172. {
  5173. // Could not find place in any of the blocks - break outer loop.
  5174. break;
  5175. }
  5176. }
  5177. /* Maximum number of tries exceeded - a very unlike event when many other
  5178. threads are simultaneously touching allocations making it impossible to make
  5179. lost at the same time as we try to allocate. */
  5180. if(tryIndex == VMA_ALLOCATION_TRY_COUNT)
  5181. {
  5182. return VK_ERROR_TOO_MANY_OBJECTS;
  5183. }
  5184. }
  5185. return VK_ERROR_OUT_OF_DEVICE_MEMORY;
  5186. }
  5187. void VmaBlockVector::Free(
  5188. VmaAllocation hAllocation)
  5189. {
  5190. VmaDeviceMemoryBlock* pBlockToDelete = VMA_NULL;
  5191. // Scope for lock.
  5192. {
  5193. VmaMutexLock lock(m_Mutex, m_hAllocator->m_UseMutex);
  5194. VmaDeviceMemoryBlock* pBlock = hAllocation->GetBlock();
  5195. if(hAllocation->IsPersistentMap())
  5196. {
  5197. pBlock->m_Mapping.Unmap(m_hAllocator, pBlock->m_hMemory);
  5198. }
  5199. pBlock->m_Metadata.Free(hAllocation);
  5200. VMA_HEAVY_ASSERT(pBlock->Validate());
  5201. VMA_DEBUG_LOG(" Freed from MemoryTypeIndex=%u", memTypeIndex);
  5202. // pBlock became empty after this deallocation.
  5203. if(pBlock->m_Metadata.IsEmpty())
  5204. {
  5205. // Already has empty Allocation. We don't want to have two, so delete this one.
  5206. if(m_HasEmptyBlock && m_Blocks.size() > m_MinBlockCount)
  5207. {
  5208. pBlockToDelete = pBlock;
  5209. Remove(pBlock);
  5210. }
  5211. // We now have first empty Allocation.
  5212. else
  5213. {
  5214. m_HasEmptyBlock = true;
  5215. }
  5216. }
  5217. // pBlock didn't become empty, but we have another empty block - find and free that one.
  5218. // (This is optional, heuristics.)
  5219. else if(m_HasEmptyBlock)
  5220. {
  5221. VmaDeviceMemoryBlock* pLastBlock = m_Blocks.back();
  5222. if(pLastBlock->m_Metadata.IsEmpty() && m_Blocks.size() > m_MinBlockCount)
  5223. {
  5224. pBlockToDelete = pLastBlock;
  5225. m_Blocks.pop_back();
  5226. m_HasEmptyBlock = false;
  5227. }
  5228. }
  5229. IncrementallySortBlocks();
  5230. }
  5231. // Destruction of a free Allocation. Deferred until this point, outside of mutex
  5232. // lock, for performance reason.
  5233. if(pBlockToDelete != VMA_NULL)
  5234. {
  5235. VMA_DEBUG_LOG(" Deleted empty allocation");
  5236. pBlockToDelete->Destroy(m_hAllocator);
  5237. vma_delete(m_hAllocator, pBlockToDelete);
  5238. }
  5239. }
  5240. void VmaBlockVector::Remove(VmaDeviceMemoryBlock* pBlock)
  5241. {
  5242. for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
  5243. {
  5244. if(m_Blocks[blockIndex] == pBlock)
  5245. {
  5246. VmaVectorRemove(m_Blocks, blockIndex);
  5247. return;
  5248. }
  5249. }
  5250. VMA_ASSERT(0);
  5251. }
  5252. void VmaBlockVector::IncrementallySortBlocks()
  5253. {
  5254. // Bubble sort only until first swap.
  5255. for(size_t i = 1; i < m_Blocks.size(); ++i)
  5256. {
  5257. if(m_Blocks[i - 1]->m_Metadata.GetSumFreeSize() > m_Blocks[i]->m_Metadata.GetSumFreeSize())
  5258. {
  5259. VMA_SWAP(m_Blocks[i - 1], m_Blocks[i]);
  5260. return;
  5261. }
  5262. }
  5263. }
  5264. VkResult VmaBlockVector::CreateBlock(VkDeviceSize blockSize, size_t* pNewBlockIndex)
  5265. {
  5266. VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
  5267. allocInfo.memoryTypeIndex = m_MemoryTypeIndex;
  5268. allocInfo.allocationSize = blockSize;
  5269. VkDeviceMemory mem = VK_NULL_HANDLE;
  5270. VkResult res = m_hAllocator->AllocateVulkanMemory(&allocInfo, &mem);
  5271. if(res < 0)
  5272. {
  5273. return res;
  5274. }
  5275. // New VkDeviceMemory successfully created.
  5276. // Create new Allocation for it.
  5277. VmaDeviceMemoryBlock* const pBlock = vma_new(m_hAllocator, VmaDeviceMemoryBlock)(m_hAllocator);
  5278. pBlock->Init(
  5279. m_MemoryTypeIndex,
  5280. mem,
  5281. allocInfo.allocationSize);
  5282. m_Blocks.push_back(pBlock);
  5283. if(pNewBlockIndex != VMA_NULL)
  5284. {
  5285. *pNewBlockIndex = m_Blocks.size() - 1;
  5286. }
  5287. return VK_SUCCESS;
  5288. }
  5289. #if VMA_STATS_STRING_ENABLED
  5290. void VmaBlockVector::PrintDetailedMap(class VmaJsonWriter& json)
  5291. {
  5292. VmaMutexLock lock(m_Mutex, m_hAllocator->m_UseMutex);
  5293. json.BeginObject();
  5294. if(m_IsCustomPool)
  5295. {
  5296. json.WriteString("MemoryTypeIndex");
  5297. json.WriteNumber(m_MemoryTypeIndex);
  5298. json.WriteString("BlockSize");
  5299. json.WriteNumber(m_PreferredBlockSize);
  5300. json.WriteString("BlockCount");
  5301. json.BeginObject(true);
  5302. if(m_MinBlockCount > 0)
  5303. {
  5304. json.WriteString("Min");
  5305. json.WriteNumber(m_MinBlockCount);
  5306. }
  5307. if(m_MaxBlockCount < SIZE_MAX)
  5308. {
  5309. json.WriteString("Max");
  5310. json.WriteNumber(m_MaxBlockCount);
  5311. }
  5312. json.WriteString("Cur");
  5313. json.WriteNumber(m_Blocks.size());
  5314. json.EndObject();
  5315. if(m_FrameInUseCount > 0)
  5316. {
  5317. json.WriteString("FrameInUseCount");
  5318. json.WriteNumber(m_FrameInUseCount);
  5319. }
  5320. }
  5321. else
  5322. {
  5323. json.WriteString("PreferredBlockSize");
  5324. json.WriteNumber(m_PreferredBlockSize);
  5325. }
  5326. json.WriteString("Blocks");
  5327. json.BeginArray();
  5328. for(size_t i = 0; i < m_Blocks.size(); ++i)
  5329. {
  5330. m_Blocks[i]->m_Metadata.PrintDetailedMap(json);
  5331. }
  5332. json.EndArray();
  5333. json.EndObject();
  5334. }
  5335. #endif // #if VMA_STATS_STRING_ENABLED
  5336. VmaDefragmentator* VmaBlockVector::EnsureDefragmentator(
  5337. VmaAllocator hAllocator,
  5338. uint32_t currentFrameIndex)
  5339. {
  5340. if(m_pDefragmentator == VMA_NULL)
  5341. {
  5342. m_pDefragmentator = vma_new(m_hAllocator, VmaDefragmentator)(
  5343. hAllocator,
  5344. this,
  5345. currentFrameIndex);
  5346. }
  5347. return m_pDefragmentator;
  5348. }
  5349. VkResult VmaBlockVector::Defragment(
  5350. VmaDefragmentationStats* pDefragmentationStats,
  5351. VkDeviceSize& maxBytesToMove,
  5352. uint32_t& maxAllocationsToMove)
  5353. {
  5354. if(m_pDefragmentator == VMA_NULL)
  5355. {
  5356. return VK_SUCCESS;
  5357. }
  5358. VmaMutexLock lock(m_Mutex, m_hAllocator->m_UseMutex);
  5359. // Defragment.
  5360. VkResult result = m_pDefragmentator->Defragment(maxBytesToMove, maxAllocationsToMove);
  5361. // Accumulate statistics.
  5362. if(pDefragmentationStats != VMA_NULL)
  5363. {
  5364. const VkDeviceSize bytesMoved = m_pDefragmentator->GetBytesMoved();
  5365. const uint32_t allocationsMoved = m_pDefragmentator->GetAllocationsMoved();
  5366. pDefragmentationStats->bytesMoved += bytesMoved;
  5367. pDefragmentationStats->allocationsMoved += allocationsMoved;
  5368. VMA_ASSERT(bytesMoved <= maxBytesToMove);
  5369. VMA_ASSERT(allocationsMoved <= maxAllocationsToMove);
  5370. maxBytesToMove -= bytesMoved;
  5371. maxAllocationsToMove -= allocationsMoved;
  5372. }
  5373. // Free empty blocks.
  5374. m_HasEmptyBlock = false;
  5375. for(size_t blockIndex = m_Blocks.size(); blockIndex--; )
  5376. {
  5377. VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex];
  5378. if(pBlock->m_Metadata.IsEmpty())
  5379. {
  5380. if(m_Blocks.size() > m_MinBlockCount)
  5381. {
  5382. if(pDefragmentationStats != VMA_NULL)
  5383. {
  5384. ++pDefragmentationStats->deviceMemoryBlocksFreed;
  5385. pDefragmentationStats->bytesFreed += pBlock->m_Metadata.GetSize();
  5386. }
  5387. VmaVectorRemove(m_Blocks, blockIndex);
  5388. pBlock->Destroy(m_hAllocator);
  5389. vma_delete(m_hAllocator, pBlock);
  5390. }
  5391. else
  5392. {
  5393. m_HasEmptyBlock = true;
  5394. }
  5395. }
  5396. }
  5397. return result;
  5398. }
  5399. void VmaBlockVector::DestroyDefragmentator()
  5400. {
  5401. if(m_pDefragmentator != VMA_NULL)
  5402. {
  5403. vma_delete(m_hAllocator, m_pDefragmentator);
  5404. m_pDefragmentator = VMA_NULL;
  5405. }
  5406. }
  5407. void VmaBlockVector::MakePoolAllocationsLost(
  5408. uint32_t currentFrameIndex,
  5409. size_t* pLostAllocationCount)
  5410. {
  5411. VmaMutexLock lock(m_Mutex, m_hAllocator->m_UseMutex);
  5412. for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
  5413. {
  5414. VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex];
  5415. VMA_ASSERT(pBlock);
  5416. pBlock->m_Metadata.MakeAllocationsLost(currentFrameIndex, m_FrameInUseCount);
  5417. }
  5418. }
  5419. void VmaBlockVector::AddStats(VmaStats* pStats)
  5420. {
  5421. const uint32_t memTypeIndex = m_MemoryTypeIndex;
  5422. const uint32_t memHeapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(memTypeIndex);
  5423. VmaMutexLock lock(m_Mutex, m_hAllocator->m_UseMutex);
  5424. for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
  5425. {
  5426. const VmaDeviceMemoryBlock* const pBlock = m_Blocks[blockIndex];
  5427. VMA_ASSERT(pBlock);
  5428. VMA_HEAVY_ASSERT(pBlock->Validate());
  5429. VmaStatInfo allocationStatInfo;
  5430. pBlock->m_Metadata.CalcAllocationStatInfo(allocationStatInfo);
  5431. VmaAddStatInfo(pStats->total, allocationStatInfo);
  5432. VmaAddStatInfo(pStats->memoryType[memTypeIndex], allocationStatInfo);
  5433. VmaAddStatInfo(pStats->memoryHeap[memHeapIndex], allocationStatInfo);
  5434. }
  5435. }
  5436. ////////////////////////////////////////////////////////////////////////////////
  5437. // VmaDefragmentator members definition
  5438. VmaDefragmentator::VmaDefragmentator(
  5439. VmaAllocator hAllocator,
  5440. VmaBlockVector* pBlockVector,
  5441. uint32_t currentFrameIndex) :
  5442. m_hAllocator(hAllocator),
  5443. m_pBlockVector(pBlockVector),
  5444. m_CurrentFrameIndex(currentFrameIndex),
  5445. m_BytesMoved(0),
  5446. m_AllocationsMoved(0),
  5447. m_Allocations(VmaStlAllocator<AllocationInfo>(hAllocator->GetAllocationCallbacks())),
  5448. m_Blocks(VmaStlAllocator<BlockInfo*>(hAllocator->GetAllocationCallbacks()))
  5449. {
  5450. }
  5451. VmaDefragmentator::~VmaDefragmentator()
  5452. {
  5453. for(size_t i = m_Blocks.size(); i--; )
  5454. {
  5455. vma_delete(m_hAllocator, m_Blocks[i]);
  5456. }
  5457. }
  5458. void VmaDefragmentator::AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged)
  5459. {
  5460. AllocationInfo allocInfo;
  5461. allocInfo.m_hAllocation = hAlloc;
  5462. allocInfo.m_pChanged = pChanged;
  5463. m_Allocations.push_back(allocInfo);
  5464. }
  5465. VkResult VmaDefragmentator::BlockInfo::EnsureMapping(VmaAllocator hAllocator, void** ppMappedData)
  5466. {
  5467. // It has already been mapped for defragmentation.
  5468. if(m_pMappedDataForDefragmentation)
  5469. {
  5470. *ppMappedData = m_pMappedDataForDefragmentation;
  5471. return VK_SUCCESS;
  5472. }
  5473. // It is originally mapped.
  5474. if(m_pBlock->m_Mapping.GetMappedData())
  5475. {
  5476. *ppMappedData = m_pBlock->m_Mapping.GetMappedData();
  5477. return VK_SUCCESS;
  5478. }
  5479. // Map on first usage.
  5480. VkResult res = m_pBlock->Map(hAllocator, &m_pMappedDataForDefragmentation);
  5481. *ppMappedData = m_pMappedDataForDefragmentation;
  5482. return res;
  5483. }
  5484. void VmaDefragmentator::BlockInfo::Unmap(VmaAllocator hAllocator)
  5485. {
  5486. if(m_pMappedDataForDefragmentation != VMA_NULL)
  5487. {
  5488. m_pBlock->Unmap(hAllocator);
  5489. }
  5490. }
  5491. VkResult VmaDefragmentator::DefragmentRound(
  5492. VkDeviceSize maxBytesToMove,
  5493. uint32_t maxAllocationsToMove)
  5494. {
  5495. if(m_Blocks.empty())
  5496. {
  5497. return VK_SUCCESS;
  5498. }
  5499. size_t srcBlockIndex = m_Blocks.size() - 1;
  5500. size_t srcAllocIndex = SIZE_MAX;
  5501. for(;;)
  5502. {
  5503. // 1. Find next allocation to move.
  5504. // 1.1. Start from last to first m_Blocks - they are sorted from most "destination" to most "source".
  5505. // 1.2. Then start from last to first m_Allocations - they are sorted from largest to smallest.
  5506. while(srcAllocIndex >= m_Blocks[srcBlockIndex]->m_Allocations.size())
  5507. {
  5508. if(m_Blocks[srcBlockIndex]->m_Allocations.empty())
  5509. {
  5510. // Finished: no more allocations to process.
  5511. if(srcBlockIndex == 0)
  5512. {
  5513. return VK_SUCCESS;
  5514. }
  5515. else
  5516. {
  5517. --srcBlockIndex;
  5518. srcAllocIndex = SIZE_MAX;
  5519. }
  5520. }
  5521. else
  5522. {
  5523. srcAllocIndex = m_Blocks[srcBlockIndex]->m_Allocations.size() - 1;
  5524. }
  5525. }
  5526. BlockInfo* pSrcBlockInfo = m_Blocks[srcBlockIndex];
  5527. AllocationInfo& allocInfo = pSrcBlockInfo->m_Allocations[srcAllocIndex];
  5528. const VkDeviceSize size = allocInfo.m_hAllocation->GetSize();
  5529. const VkDeviceSize srcOffset = allocInfo.m_hAllocation->GetOffset();
  5530. const VkDeviceSize alignment = allocInfo.m_hAllocation->GetAlignment();
  5531. const VmaSuballocationType suballocType = allocInfo.m_hAllocation->GetSuballocationType();
  5532. // 2. Try to find new place for this allocation in preceding or current block.
  5533. for(size_t dstBlockIndex = 0; dstBlockIndex <= srcBlockIndex; ++dstBlockIndex)
  5534. {
  5535. BlockInfo* pDstBlockInfo = m_Blocks[dstBlockIndex];
  5536. VmaAllocationRequest dstAllocRequest;
  5537. if(pDstBlockInfo->m_pBlock->m_Metadata.CreateAllocationRequest(
  5538. m_CurrentFrameIndex,
  5539. m_pBlockVector->GetFrameInUseCount(),
  5540. m_pBlockVector->GetBufferImageGranularity(),
  5541. size,
  5542. alignment,
  5543. suballocType,
  5544. false, // canMakeOtherLost
  5545. &dstAllocRequest) &&
  5546. MoveMakesSense(
  5547. dstBlockIndex, dstAllocRequest.offset, srcBlockIndex, srcOffset))
  5548. {
  5549. VMA_ASSERT(dstAllocRequest.itemsToMakeLostCount == 0);
  5550. // Reached limit on number of allocations or bytes to move.
  5551. if((m_AllocationsMoved + 1 > maxAllocationsToMove) ||
  5552. (m_BytesMoved + size > maxBytesToMove))
  5553. {
  5554. return VK_INCOMPLETE;
  5555. }
  5556. void* pDstMappedData = VMA_NULL;
  5557. VkResult res = pDstBlockInfo->EnsureMapping(m_hAllocator, &pDstMappedData);
  5558. if(res != VK_SUCCESS)
  5559. {
  5560. return res;
  5561. }
  5562. void* pSrcMappedData = VMA_NULL;
  5563. res = pSrcBlockInfo->EnsureMapping(m_hAllocator, &pSrcMappedData);
  5564. if(res != VK_SUCCESS)
  5565. {
  5566. return res;
  5567. }
  5568. // THE PLACE WHERE ACTUAL DATA COPY HAPPENS.
  5569. memcpy(
  5570. reinterpret_cast<char*>(pDstMappedData) + dstAllocRequest.offset,
  5571. reinterpret_cast<char*>(pSrcMappedData) + srcOffset,
  5572. static_cast<size_t>(size));
  5573. pDstBlockInfo->m_pBlock->m_Metadata.Alloc(dstAllocRequest, suballocType, size, allocInfo.m_hAllocation);
  5574. pSrcBlockInfo->m_pBlock->m_Metadata.Free(allocInfo.m_hAllocation);
  5575. allocInfo.m_hAllocation->ChangeBlockAllocation(pDstBlockInfo->m_pBlock, dstAllocRequest.offset);
  5576. if(allocInfo.m_pChanged != VMA_NULL)
  5577. {
  5578. *allocInfo.m_pChanged = VK_TRUE;
  5579. }
  5580. ++m_AllocationsMoved;
  5581. m_BytesMoved += size;
  5582. VmaVectorRemove(pSrcBlockInfo->m_Allocations, srcAllocIndex);
  5583. break;
  5584. }
  5585. }
  5586. // If not processed, this allocInfo remains in pBlockInfo->m_Allocations for next round.
  5587. if(srcAllocIndex > 0)
  5588. {
  5589. --srcAllocIndex;
  5590. }
  5591. else
  5592. {
  5593. if(srcBlockIndex > 0)
  5594. {
  5595. --srcBlockIndex;
  5596. srcAllocIndex = SIZE_MAX;
  5597. }
  5598. else
  5599. {
  5600. return VK_SUCCESS;
  5601. }
  5602. }
  5603. }
  5604. }
  5605. VkResult VmaDefragmentator::Defragment(
  5606. VkDeviceSize maxBytesToMove,
  5607. uint32_t maxAllocationsToMove)
  5608. {
  5609. if(m_Allocations.empty())
  5610. {
  5611. return VK_SUCCESS;
  5612. }
  5613. // Create block info for each block.
  5614. const size_t blockCount = m_pBlockVector->m_Blocks.size();
  5615. for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
  5616. {
  5617. BlockInfo* pBlockInfo = vma_new(m_hAllocator, BlockInfo)(m_hAllocator->GetAllocationCallbacks());
  5618. pBlockInfo->m_pBlock = m_pBlockVector->m_Blocks[blockIndex];
  5619. m_Blocks.push_back(pBlockInfo);
  5620. }
  5621. // Sort them by m_pBlock pointer value.
  5622. VMA_SORT(m_Blocks.begin(), m_Blocks.end(), BlockPointerLess());
  5623. // Move allocation infos from m_Allocations to appropriate m_Blocks[memTypeIndex].m_Allocations.
  5624. for(size_t blockIndex = 0, allocCount = m_Allocations.size(); blockIndex < allocCount; ++blockIndex)
  5625. {
  5626. AllocationInfo& allocInfo = m_Allocations[blockIndex];
  5627. // Now as we are inside VmaBlockVector::m_Mutex, we can make final check if this allocation was not lost.
  5628. if(allocInfo.m_hAllocation->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST)
  5629. {
  5630. VmaDeviceMemoryBlock* pBlock = allocInfo.m_hAllocation->GetBlock();
  5631. BlockInfoVector::iterator it = VmaBinaryFindFirstNotLess(m_Blocks.begin(), m_Blocks.end(), pBlock, BlockPointerLess());
  5632. if(it != m_Blocks.end() && (*it)->m_pBlock == pBlock)
  5633. {
  5634. (*it)->m_Allocations.push_back(allocInfo);
  5635. }
  5636. else
  5637. {
  5638. VMA_ASSERT(0);
  5639. }
  5640. }
  5641. }
  5642. m_Allocations.clear();
  5643. for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
  5644. {
  5645. BlockInfo* pBlockInfo = m_Blocks[blockIndex];
  5646. pBlockInfo->CalcHasNonMovableAllocations();
  5647. pBlockInfo->SortAllocationsBySizeDescecnding();
  5648. }
  5649. // Sort m_Blocks this time by the main criterium, from most "destination" to most "source" blocks.
  5650. VMA_SORT(m_Blocks.begin(), m_Blocks.end(), BlockInfoCompareMoveDestination());
  5651. // Execute defragmentation rounds (the main part).
  5652. VkResult result = VK_SUCCESS;
  5653. for(size_t round = 0; (round < 2) && (result == VK_SUCCESS); ++round)
  5654. {
  5655. result = DefragmentRound(maxBytesToMove, maxAllocationsToMove);
  5656. }
  5657. // Unmap blocks that were mapped for defragmentation.
  5658. for(size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
  5659. {
  5660. m_Blocks[blockIndex]->Unmap(m_hAllocator);
  5661. }
  5662. return result;
  5663. }
  5664. bool VmaDefragmentator::MoveMakesSense(
  5665. size_t dstBlockIndex, VkDeviceSize dstOffset,
  5666. size_t srcBlockIndex, VkDeviceSize srcOffset)
  5667. {
  5668. if(dstBlockIndex < srcBlockIndex)
  5669. {
  5670. return true;
  5671. }
  5672. if(dstBlockIndex > srcBlockIndex)
  5673. {
  5674. return false;
  5675. }
  5676. if(dstOffset < srcOffset)
  5677. {
  5678. return true;
  5679. }
  5680. return false;
  5681. }
  5682. ////////////////////////////////////////////////////////////////////////////////
  5683. // VmaAllocator_T
  5684. VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) :
  5685. m_UseMutex((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT) == 0),
  5686. m_UseKhrDedicatedAllocation((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0),
  5687. m_PhysicalDevice(pCreateInfo->physicalDevice),
  5688. m_hDevice(pCreateInfo->device),
  5689. m_AllocationCallbacksSpecified(pCreateInfo->pAllocationCallbacks != VMA_NULL),
  5690. m_AllocationCallbacks(pCreateInfo->pAllocationCallbacks ?
  5691. *pCreateInfo->pAllocationCallbacks : VmaEmptyAllocationCallbacks),
  5692. m_PreferredLargeHeapBlockSize(0),
  5693. m_PreferredSmallHeapBlockSize(0),
  5694. m_CurrentFrameIndex(0),
  5695. m_Pools(VmaStlAllocator<VmaPool>(GetAllocationCallbacks()))
  5696. {
  5697. VMA_ASSERT(pCreateInfo->physicalDevice && pCreateInfo->device);
  5698. memset(&m_DeviceMemoryCallbacks, 0 ,sizeof(m_DeviceMemoryCallbacks));
  5699. memset(&m_MemProps, 0, sizeof(m_MemProps));
  5700. memset(&m_PhysicalDeviceProperties, 0, sizeof(m_PhysicalDeviceProperties));
  5701. memset(&m_pBlockVectors, 0, sizeof(m_pBlockVectors));
  5702. memset(&m_pDedicatedAllocations, 0, sizeof(m_pDedicatedAllocations));
  5703. for(uint32_t i = 0; i < VK_MAX_MEMORY_HEAPS; ++i)
  5704. {
  5705. m_HeapSizeLimit[i] = VK_WHOLE_SIZE;
  5706. }
  5707. if(pCreateInfo->pDeviceMemoryCallbacks != VMA_NULL)
  5708. {
  5709. m_DeviceMemoryCallbacks.pfnAllocate = pCreateInfo->pDeviceMemoryCallbacks->pfnAllocate;
  5710. m_DeviceMemoryCallbacks.pfnFree = pCreateInfo->pDeviceMemoryCallbacks->pfnFree;
  5711. }
  5712. ImportVulkanFunctions(pCreateInfo->pVulkanFunctions);
  5713. (*m_VulkanFunctions.vkGetPhysicalDeviceProperties)(m_PhysicalDevice, &m_PhysicalDeviceProperties);
  5714. (*m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties)(m_PhysicalDevice, &m_MemProps);
  5715. m_PreferredLargeHeapBlockSize = (pCreateInfo->preferredLargeHeapBlockSize != 0) ?
  5716. pCreateInfo->preferredLargeHeapBlockSize : static_cast<VkDeviceSize>(VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE);
  5717. m_PreferredSmallHeapBlockSize = (pCreateInfo->preferredSmallHeapBlockSize != 0) ?
  5718. pCreateInfo->preferredSmallHeapBlockSize : static_cast<VkDeviceSize>(VMA_DEFAULT_SMALL_HEAP_BLOCK_SIZE);
  5719. if(pCreateInfo->pHeapSizeLimit != VMA_NULL)
  5720. {
  5721. for(uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex)
  5722. {
  5723. const VkDeviceSize limit = pCreateInfo->pHeapSizeLimit[heapIndex];
  5724. if(limit != VK_WHOLE_SIZE)
  5725. {
  5726. m_HeapSizeLimit[heapIndex] = limit;
  5727. if(limit < m_MemProps.memoryHeaps[heapIndex].size)
  5728. {
  5729. m_MemProps.memoryHeaps[heapIndex].size = limit;
  5730. }
  5731. }
  5732. }
  5733. }
  5734. for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
  5735. {
  5736. const VkDeviceSize preferredBlockSize = CalcPreferredBlockSize(memTypeIndex);
  5737. m_pBlockVectors[memTypeIndex] = vma_new(this, VmaBlockVector)(
  5738. this,
  5739. memTypeIndex,
  5740. preferredBlockSize,
  5741. 0,
  5742. SIZE_MAX,
  5743. GetBufferImageGranularity(),
  5744. pCreateInfo->frameInUseCount,
  5745. false); // isCustomPool
  5746. // No need to call m_pBlockVectors[memTypeIndex][blockVectorTypeIndex]->CreateMinBlocks here,
  5747. // becase minBlockCount is 0.
  5748. m_pDedicatedAllocations[memTypeIndex] = vma_new(this, AllocationVectorType)(VmaStlAllocator<VmaAllocation>(GetAllocationCallbacks()));
  5749. }
  5750. }
  5751. VmaAllocator_T::~VmaAllocator_T()
  5752. {
  5753. VMA_ASSERT(m_Pools.empty());
  5754. for(size_t i = GetMemoryTypeCount(); i--; )
  5755. {
  5756. vma_delete(this, m_pDedicatedAllocations[i]);
  5757. vma_delete(this, m_pBlockVectors[i]);
  5758. }
  5759. }
  5760. void VmaAllocator_T::ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunctions)
  5761. {
  5762. #if VMA_STATIC_VULKAN_FUNCTIONS == 1
  5763. m_VulkanFunctions.vkGetPhysicalDeviceProperties = &vkGetPhysicalDeviceProperties;
  5764. m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties = &vkGetPhysicalDeviceMemoryProperties;
  5765. m_VulkanFunctions.vkAllocateMemory = &vkAllocateMemory;
  5766. m_VulkanFunctions.vkFreeMemory = &vkFreeMemory;
  5767. m_VulkanFunctions.vkMapMemory = &vkMapMemory;
  5768. m_VulkanFunctions.vkUnmapMemory = &vkUnmapMemory;
  5769. m_VulkanFunctions.vkBindBufferMemory = &vkBindBufferMemory;
  5770. m_VulkanFunctions.vkBindImageMemory = &vkBindImageMemory;
  5771. m_VulkanFunctions.vkGetBufferMemoryRequirements = &vkGetBufferMemoryRequirements;
  5772. m_VulkanFunctions.vkGetImageMemoryRequirements = &vkGetImageMemoryRequirements;
  5773. m_VulkanFunctions.vkCreateBuffer = &vkCreateBuffer;
  5774. m_VulkanFunctions.vkDestroyBuffer = &vkDestroyBuffer;
  5775. m_VulkanFunctions.vkCreateImage = &vkCreateImage;
  5776. m_VulkanFunctions.vkDestroyImage = &vkDestroyImage;
  5777. if(m_UseKhrDedicatedAllocation)
  5778. {
  5779. m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR =
  5780. (PFN_vkGetBufferMemoryRequirements2KHR)vkGetDeviceProcAddr(m_hDevice, "vkGetBufferMemoryRequirements2KHR");
  5781. m_VulkanFunctions.vkGetImageMemoryRequirements2KHR =
  5782. (PFN_vkGetImageMemoryRequirements2KHR)vkGetDeviceProcAddr(m_hDevice, "vkGetImageMemoryRequirements2KHR");
  5783. }
  5784. #endif // #if VMA_STATIC_VULKAN_FUNCTIONS == 1
  5785. #define VMA_COPY_IF_NOT_NULL(funcName) \
  5786. if(pVulkanFunctions->funcName != VMA_NULL) m_VulkanFunctions.funcName = pVulkanFunctions->funcName;
  5787. if(pVulkanFunctions != VMA_NULL)
  5788. {
  5789. VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceProperties);
  5790. VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceMemoryProperties);
  5791. VMA_COPY_IF_NOT_NULL(vkAllocateMemory);
  5792. VMA_COPY_IF_NOT_NULL(vkFreeMemory);
  5793. VMA_COPY_IF_NOT_NULL(vkMapMemory);
  5794. VMA_COPY_IF_NOT_NULL(vkUnmapMemory);
  5795. VMA_COPY_IF_NOT_NULL(vkBindBufferMemory);
  5796. VMA_COPY_IF_NOT_NULL(vkBindImageMemory);
  5797. VMA_COPY_IF_NOT_NULL(vkGetBufferMemoryRequirements);
  5798. VMA_COPY_IF_NOT_NULL(vkGetImageMemoryRequirements);
  5799. VMA_COPY_IF_NOT_NULL(vkCreateBuffer);
  5800. VMA_COPY_IF_NOT_NULL(vkDestroyBuffer);
  5801. VMA_COPY_IF_NOT_NULL(vkCreateImage);
  5802. VMA_COPY_IF_NOT_NULL(vkDestroyImage);
  5803. VMA_COPY_IF_NOT_NULL(vkGetBufferMemoryRequirements2KHR);
  5804. VMA_COPY_IF_NOT_NULL(vkGetImageMemoryRequirements2KHR);
  5805. }
  5806. #undef VMA_COPY_IF_NOT_NULL
  5807. // If these asserts are hit, you must either #define VMA_STATIC_VULKAN_FUNCTIONS 1
  5808. // or pass valid pointers as VmaAllocatorCreateInfo::pVulkanFunctions.
  5809. VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceProperties != VMA_NULL);
  5810. VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties != VMA_NULL);
  5811. VMA_ASSERT(m_VulkanFunctions.vkAllocateMemory != VMA_NULL);
  5812. VMA_ASSERT(m_VulkanFunctions.vkFreeMemory != VMA_NULL);
  5813. VMA_ASSERT(m_VulkanFunctions.vkMapMemory != VMA_NULL);
  5814. VMA_ASSERT(m_VulkanFunctions.vkUnmapMemory != VMA_NULL);
  5815. VMA_ASSERT(m_VulkanFunctions.vkBindBufferMemory != VMA_NULL);
  5816. VMA_ASSERT(m_VulkanFunctions.vkBindImageMemory != VMA_NULL);
  5817. VMA_ASSERT(m_VulkanFunctions.vkGetBufferMemoryRequirements != VMA_NULL);
  5818. VMA_ASSERT(m_VulkanFunctions.vkGetImageMemoryRequirements != VMA_NULL);
  5819. VMA_ASSERT(m_VulkanFunctions.vkCreateBuffer != VMA_NULL);
  5820. VMA_ASSERT(m_VulkanFunctions.vkDestroyBuffer != VMA_NULL);
  5821. VMA_ASSERT(m_VulkanFunctions.vkCreateImage != VMA_NULL);
  5822. VMA_ASSERT(m_VulkanFunctions.vkDestroyImage != VMA_NULL);
  5823. if(m_UseKhrDedicatedAllocation)
  5824. {
  5825. VMA_ASSERT(m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR != VMA_NULL);
  5826. VMA_ASSERT(m_VulkanFunctions.vkGetImageMemoryRequirements2KHR != VMA_NULL);
  5827. }
  5828. }
  5829. VkDeviceSize VmaAllocator_T::CalcPreferredBlockSize(uint32_t memTypeIndex)
  5830. {
  5831. const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
  5832. const VkDeviceSize heapSize = m_MemProps.memoryHeaps[heapIndex].size;
  5833. return (heapSize <= VMA_SMALL_HEAP_MAX_SIZE) ?
  5834. m_PreferredSmallHeapBlockSize : m_PreferredLargeHeapBlockSize;
  5835. }
  5836. VkResult VmaAllocator_T::AllocateMemoryOfType(
  5837. const VkMemoryRequirements& vkMemReq,
  5838. bool dedicatedAllocation,
  5839. VkBuffer dedicatedBuffer,
  5840. VkImage dedicatedImage,
  5841. const VmaAllocationCreateInfo& createInfo,
  5842. uint32_t memTypeIndex,
  5843. VmaSuballocationType suballocType,
  5844. VmaAllocation* pAllocation)
  5845. {
  5846. VMA_ASSERT(pAllocation != VMA_NULL);
  5847. VMA_DEBUG_LOG(" AllocateMemory: MemoryTypeIndex=%u, Size=%llu", memTypeIndex, vkMemReq.size);
  5848. VmaAllocationCreateInfo finalCreateInfo = createInfo;
  5849. // If memory type is not HOST_VISIBLE, disable MAPPED.
  5850. if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 &&
  5851. (m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
  5852. {
  5853. finalCreateInfo.flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT;
  5854. }
  5855. VmaBlockVector* const blockVector = m_pBlockVectors[memTypeIndex];
  5856. VMA_ASSERT(blockVector);
  5857. const VkDeviceSize preferredBlockSize = blockVector->GetPreferredBlockSize();
  5858. bool preferDedicatedMemory =
  5859. VMA_DEBUG_ALWAYS_DEDICATED_MEMORY ||
  5860. dedicatedAllocation ||
  5861. // Heuristics: Allocate dedicated memory if requested size if greater than half of preferred block size.
  5862. vkMemReq.size > preferredBlockSize / 2;
  5863. if(preferDedicatedMemory &&
  5864. (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0 &&
  5865. finalCreateInfo.pool == VK_NULL_HANDLE)
  5866. {
  5867. finalCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
  5868. }
  5869. if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0)
  5870. {
  5871. if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
  5872. {
  5873. return VK_ERROR_OUT_OF_DEVICE_MEMORY;
  5874. }
  5875. else
  5876. {
  5877. return AllocateDedicatedMemory(
  5878. vkMemReq.size,
  5879. suballocType,
  5880. memTypeIndex,
  5881. (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0,
  5882. (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0,
  5883. finalCreateInfo.pUserData,
  5884. dedicatedBuffer,
  5885. dedicatedImage,
  5886. pAllocation);
  5887. }
  5888. }
  5889. else
  5890. {
  5891. VkResult res = blockVector->Allocate(
  5892. VK_NULL_HANDLE, // hCurrentPool
  5893. m_CurrentFrameIndex.load(),
  5894. vkMemReq,
  5895. finalCreateInfo,
  5896. suballocType,
  5897. pAllocation);
  5898. if(res == VK_SUCCESS)
  5899. {
  5900. return res;
  5901. }
  5902. // 5. Try dedicated memory.
  5903. if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
  5904. {
  5905. return VK_ERROR_OUT_OF_DEVICE_MEMORY;
  5906. }
  5907. else
  5908. {
  5909. res = AllocateDedicatedMemory(
  5910. vkMemReq.size,
  5911. suballocType,
  5912. memTypeIndex,
  5913. (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0,
  5914. (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0,
  5915. finalCreateInfo.pUserData,
  5916. dedicatedBuffer,
  5917. dedicatedImage,
  5918. pAllocation);
  5919. if(res == VK_SUCCESS)
  5920. {
  5921. // Succeeded: AllocateDedicatedMemory function already filld pMemory, nothing more to do here.
  5922. VMA_DEBUG_LOG(" Allocated as DedicatedMemory");
  5923. return VK_SUCCESS;
  5924. }
  5925. else
  5926. {
  5927. // Everything failed: Return error code.
  5928. VMA_DEBUG_LOG(" vkAllocateMemory FAILED");
  5929. return res;
  5930. }
  5931. }
  5932. }
  5933. }
  5934. VkResult VmaAllocator_T::AllocateDedicatedMemory(
  5935. VkDeviceSize size,
  5936. VmaSuballocationType suballocType,
  5937. uint32_t memTypeIndex,
  5938. bool map,
  5939. bool isUserDataString,
  5940. void* pUserData,
  5941. VkBuffer dedicatedBuffer,
  5942. VkImage dedicatedImage,
  5943. VmaAllocation* pAllocation)
  5944. {
  5945. VMA_ASSERT(pAllocation);
  5946. VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
  5947. allocInfo.memoryTypeIndex = memTypeIndex;
  5948. allocInfo.allocationSize = size;
  5949. VkMemoryDedicatedAllocateInfoKHR dedicatedAllocInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR };
  5950. if(m_UseKhrDedicatedAllocation)
  5951. {
  5952. if(dedicatedBuffer != VK_NULL_HANDLE)
  5953. {
  5954. VMA_ASSERT(dedicatedImage == VK_NULL_HANDLE);
  5955. dedicatedAllocInfo.buffer = dedicatedBuffer;
  5956. allocInfo.pNext = &dedicatedAllocInfo;
  5957. }
  5958. else if(dedicatedImage != VK_NULL_HANDLE)
  5959. {
  5960. dedicatedAllocInfo.image = dedicatedImage;
  5961. allocInfo.pNext = &dedicatedAllocInfo;
  5962. }
  5963. }
  5964. // Allocate VkDeviceMemory.
  5965. VkDeviceMemory hMemory = VK_NULL_HANDLE;
  5966. VkResult res = AllocateVulkanMemory(&allocInfo, &hMemory);
  5967. if(res < 0)
  5968. {
  5969. VMA_DEBUG_LOG(" vkAllocateMemory FAILED");
  5970. return res;
  5971. }
  5972. void* pMappedData = nullptr;
  5973. if(map)
  5974. {
  5975. res = (*m_VulkanFunctions.vkMapMemory)(
  5976. m_hDevice,
  5977. hMemory,
  5978. 0,
  5979. VK_WHOLE_SIZE,
  5980. 0,
  5981. &pMappedData);
  5982. if(res < 0)
  5983. {
  5984. VMA_DEBUG_LOG(" vkMapMemory FAILED");
  5985. FreeVulkanMemory(memTypeIndex, size, hMemory);
  5986. return res;
  5987. }
  5988. }
  5989. *pAllocation = vma_new(this, VmaAllocation_T)(m_CurrentFrameIndex.load(), isUserDataString);
  5990. (*pAllocation)->InitDedicatedAllocation(memTypeIndex, hMemory, suballocType, pMappedData, size);
  5991. (*pAllocation)->SetUserData(this, pUserData);
  5992. // Register it in m_pDedicatedAllocations.
  5993. {
  5994. VmaMutexLock lock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
  5995. AllocationVectorType* pDedicatedAllocations = m_pDedicatedAllocations[memTypeIndex];
  5996. VMA_ASSERT(pDedicatedAllocations);
  5997. VmaVectorInsertSorted<VmaPointerLess>(*pDedicatedAllocations, *pAllocation);
  5998. }
  5999. VMA_DEBUG_LOG(" Allocated DedicatedMemory MemoryTypeIndex=#%u", memTypeIndex);
  6000. return VK_SUCCESS;
  6001. }
  6002. void VmaAllocator_T::GetBufferMemoryRequirements(
  6003. VkBuffer hBuffer,
  6004. VkMemoryRequirements& memReq,
  6005. bool& requiresDedicatedAllocation,
  6006. bool& prefersDedicatedAllocation) const
  6007. {
  6008. if(m_UseKhrDedicatedAllocation)
  6009. {
  6010. VkBufferMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR };
  6011. memReqInfo.buffer = hBuffer;
  6012. VkMemoryDedicatedRequirementsKHR memDedicatedReq = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR };
  6013. VkMemoryRequirements2KHR memReq2 = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR };
  6014. memReq2.pNext = &memDedicatedReq;
  6015. (*m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR)(m_hDevice, &memReqInfo, &memReq2);
  6016. memReq = memReq2.memoryRequirements;
  6017. requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE);
  6018. prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE);
  6019. }
  6020. else
  6021. {
  6022. (*m_VulkanFunctions.vkGetBufferMemoryRequirements)(m_hDevice, hBuffer, &memReq);
  6023. requiresDedicatedAllocation = false;
  6024. prefersDedicatedAllocation = false;
  6025. }
  6026. }
  6027. void VmaAllocator_T::GetImageMemoryRequirements(
  6028. VkImage hImage,
  6029. VkMemoryRequirements& memReq,
  6030. bool& requiresDedicatedAllocation,
  6031. bool& prefersDedicatedAllocation) const
  6032. {
  6033. if(m_UseKhrDedicatedAllocation)
  6034. {
  6035. VkImageMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR };
  6036. memReqInfo.image = hImage;
  6037. VkMemoryDedicatedRequirementsKHR memDedicatedReq = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR };
  6038. VkMemoryRequirements2KHR memReq2 = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR };
  6039. memReq2.pNext = &memDedicatedReq;
  6040. (*m_VulkanFunctions.vkGetImageMemoryRequirements2KHR)(m_hDevice, &memReqInfo, &memReq2);
  6041. memReq = memReq2.memoryRequirements;
  6042. requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE);
  6043. prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE);
  6044. }
  6045. else
  6046. {
  6047. (*m_VulkanFunctions.vkGetImageMemoryRequirements)(m_hDevice, hImage, &memReq);
  6048. requiresDedicatedAllocation = false;
  6049. prefersDedicatedAllocation = false;
  6050. }
  6051. }
  6052. VkResult VmaAllocator_T::AllocateMemory(
  6053. const VkMemoryRequirements& vkMemReq,
  6054. bool requiresDedicatedAllocation,
  6055. bool prefersDedicatedAllocation,
  6056. VkBuffer dedicatedBuffer,
  6057. VkImage dedicatedImage,
  6058. const VmaAllocationCreateInfo& createInfo,
  6059. VmaSuballocationType suballocType,
  6060. VmaAllocation* pAllocation)
  6061. {
  6062. if((createInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 &&
  6063. (createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
  6064. {
  6065. VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT together with VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT makes no sense.");
  6066. return VK_ERROR_OUT_OF_DEVICE_MEMORY;
  6067. }
  6068. if((createInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 &&
  6069. (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0)
  6070. {
  6071. VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_MAPPED_BIT together with VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT is invalid.");
  6072. return VK_ERROR_OUT_OF_DEVICE_MEMORY;
  6073. }
  6074. if(requiresDedicatedAllocation)
  6075. {
  6076. if((createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
  6077. {
  6078. VMA_ASSERT(0 && "VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT specified while dedicated allocation is required.");
  6079. return VK_ERROR_OUT_OF_DEVICE_MEMORY;
  6080. }
  6081. if(createInfo.pool != VK_NULL_HANDLE)
  6082. {
  6083. VMA_ASSERT(0 && "Pool specified while dedicated allocation is required.");
  6084. return VK_ERROR_OUT_OF_DEVICE_MEMORY;
  6085. }
  6086. }
  6087. if((createInfo.pool != VK_NULL_HANDLE) &&
  6088. ((createInfo.flags & (VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT)) != 0))
  6089. {
  6090. VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT when pool != null is invalid.");
  6091. return VK_ERROR_OUT_OF_DEVICE_MEMORY;
  6092. }
  6093. if(createInfo.pool != VK_NULL_HANDLE)
  6094. {
  6095. return createInfo.pool->m_BlockVector.Allocate(
  6096. createInfo.pool,
  6097. m_CurrentFrameIndex.load(),
  6098. vkMemReq,
  6099. createInfo,
  6100. suballocType,
  6101. pAllocation);
  6102. }
  6103. else
  6104. {
  6105. // Bit mask of memory Vulkan types acceptable for this allocation.
  6106. uint32_t memoryTypeBits = vkMemReq.memoryTypeBits;
  6107. uint32_t memTypeIndex = UINT32_MAX;
  6108. VkResult res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &createInfo, &memTypeIndex);
  6109. if(res == VK_SUCCESS)
  6110. {
  6111. res = AllocateMemoryOfType(
  6112. vkMemReq,
  6113. requiresDedicatedAllocation || prefersDedicatedAllocation,
  6114. dedicatedBuffer,
  6115. dedicatedImage,
  6116. createInfo,
  6117. memTypeIndex,
  6118. suballocType,
  6119. pAllocation);
  6120. // Succeeded on first try.
  6121. if(res == VK_SUCCESS)
  6122. {
  6123. return res;
  6124. }
  6125. // Allocation from this memory type failed. Try other compatible memory types.
  6126. else
  6127. {
  6128. for(;;)
  6129. {
  6130. // Remove old memTypeIndex from list of possibilities.
  6131. memoryTypeBits &= ~(1u << memTypeIndex);
  6132. // Find alternative memTypeIndex.
  6133. res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &createInfo, &memTypeIndex);
  6134. if(res == VK_SUCCESS)
  6135. {
  6136. res = AllocateMemoryOfType(
  6137. vkMemReq,
  6138. requiresDedicatedAllocation || prefersDedicatedAllocation,
  6139. dedicatedBuffer,
  6140. dedicatedImage,
  6141. createInfo,
  6142. memTypeIndex,
  6143. suballocType,
  6144. pAllocation);
  6145. // Allocation from this alternative memory type succeeded.
  6146. if(res == VK_SUCCESS)
  6147. {
  6148. return res;
  6149. }
  6150. // else: Allocation from this memory type failed. Try next one - next loop iteration.
  6151. }
  6152. // No other matching memory type index could be found.
  6153. else
  6154. {
  6155. // Not returning res, which is VK_ERROR_FEATURE_NOT_PRESENT, because we already failed to allocate once.
  6156. return VK_ERROR_OUT_OF_DEVICE_MEMORY;
  6157. }
  6158. }
  6159. }
  6160. }
  6161. // Can't find any single memory type maching requirements. res is VK_ERROR_FEATURE_NOT_PRESENT.
  6162. else
  6163. return res;
  6164. }
  6165. }
  6166. void VmaAllocator_T::FreeMemory(const VmaAllocation allocation)
  6167. {
  6168. VMA_ASSERT(allocation);
  6169. if(allocation->CanBecomeLost() == false ||
  6170. allocation->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST)
  6171. {
  6172. switch(allocation->GetType())
  6173. {
  6174. case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
  6175. {
  6176. VmaBlockVector* pBlockVector = VMA_NULL;
  6177. VmaPool hPool = allocation->GetPool();
  6178. if(hPool != VK_NULL_HANDLE)
  6179. {
  6180. pBlockVector = &hPool->m_BlockVector;
  6181. }
  6182. else
  6183. {
  6184. const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex();
  6185. pBlockVector = m_pBlockVectors[memTypeIndex];
  6186. }
  6187. pBlockVector->Free(allocation);
  6188. }
  6189. break;
  6190. case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
  6191. FreeDedicatedMemory(allocation);
  6192. break;
  6193. default:
  6194. VMA_ASSERT(0);
  6195. }
  6196. }
  6197. allocation->SetUserData(this, VMA_NULL);
  6198. vma_delete(this, allocation);
  6199. }
  6200. void VmaAllocator_T::CalculateStats(VmaStats* pStats)
  6201. {
  6202. // Initialize.
  6203. InitStatInfo(pStats->total);
  6204. for(size_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i)
  6205. InitStatInfo(pStats->memoryType[i]);
  6206. for(size_t i = 0; i < VK_MAX_MEMORY_HEAPS; ++i)
  6207. InitStatInfo(pStats->memoryHeap[i]);
  6208. // Process default pools.
  6209. for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
  6210. {
  6211. const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
  6212. VmaBlockVector* const pBlockVector = m_pBlockVectors[memTypeIndex];
  6213. VMA_ASSERT(pBlockVector);
  6214. pBlockVector->AddStats(pStats);
  6215. }
  6216. // Process custom pools.
  6217. {
  6218. VmaMutexLock lock(m_PoolsMutex, m_UseMutex);
  6219. for(size_t poolIndex = 0, poolCount = m_Pools.size(); poolIndex < poolCount; ++poolIndex)
  6220. {
  6221. m_Pools[poolIndex]->GetBlockVector().AddStats(pStats);
  6222. }
  6223. }
  6224. // Process dedicated allocations.
  6225. for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
  6226. {
  6227. const uint32_t memHeapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
  6228. VmaMutexLock dedicatedAllocationsLock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
  6229. AllocationVectorType* const pDedicatedAllocVector = m_pDedicatedAllocations[memTypeIndex];
  6230. VMA_ASSERT(pDedicatedAllocVector);
  6231. for(size_t allocIndex = 0, allocCount = pDedicatedAllocVector->size(); allocIndex < allocCount; ++allocIndex)
  6232. {
  6233. VmaStatInfo allocationStatInfo;
  6234. (*pDedicatedAllocVector)[allocIndex]->DedicatedAllocCalcStatsInfo(allocationStatInfo);
  6235. VmaAddStatInfo(pStats->total, allocationStatInfo);
  6236. VmaAddStatInfo(pStats->memoryType[memTypeIndex], allocationStatInfo);
  6237. VmaAddStatInfo(pStats->memoryHeap[memHeapIndex], allocationStatInfo);
  6238. }
  6239. }
  6240. // Postprocess.
  6241. VmaPostprocessCalcStatInfo(pStats->total);
  6242. for(size_t i = 0; i < GetMemoryTypeCount(); ++i)
  6243. VmaPostprocessCalcStatInfo(pStats->memoryType[i]);
  6244. for(size_t i = 0; i < GetMemoryHeapCount(); ++i)
  6245. VmaPostprocessCalcStatInfo(pStats->memoryHeap[i]);
  6246. }
  6247. static const uint32_t VMA_VENDOR_ID_AMD = 4098;
  6248. VkResult VmaAllocator_T::Defragment(
  6249. VmaAllocation* pAllocations,
  6250. size_t allocationCount,
  6251. VkBool32* pAllocationsChanged,
  6252. const VmaDefragmentationInfo* pDefragmentationInfo,
  6253. VmaDefragmentationStats* pDefragmentationStats)
  6254. {
  6255. if(pAllocationsChanged != VMA_NULL)
  6256. {
  6257. memset(pAllocationsChanged, 0, sizeof(*pAllocationsChanged));
  6258. }
  6259. if(pDefragmentationStats != VMA_NULL)
  6260. {
  6261. memset(pDefragmentationStats, 0, sizeof(*pDefragmentationStats));
  6262. }
  6263. const uint32_t currentFrameIndex = m_CurrentFrameIndex.load();
  6264. VmaMutexLock poolsLock(m_PoolsMutex, m_UseMutex);
  6265. const size_t poolCount = m_Pools.size();
  6266. // Dispatch pAllocations among defragmentators. Create them in BlockVectors when necessary.
  6267. for(size_t allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
  6268. {
  6269. VmaAllocation hAlloc = pAllocations[allocIndex];
  6270. VMA_ASSERT(hAlloc);
  6271. const uint32_t memTypeIndex = hAlloc->GetMemoryTypeIndex();
  6272. // DedicatedAlloc cannot be defragmented.
  6273. if((hAlloc->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK) &&
  6274. // Only HOST_VISIBLE memory types can be defragmented.
  6275. ((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0) &&
  6276. // Lost allocation cannot be defragmented.
  6277. (hAlloc->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST))
  6278. {
  6279. VmaBlockVector* pAllocBlockVector = nullptr;
  6280. const VmaPool hAllocPool = hAlloc->GetPool();
  6281. // This allocation belongs to custom pool.
  6282. if(hAllocPool != VK_NULL_HANDLE)
  6283. {
  6284. pAllocBlockVector = &hAllocPool->GetBlockVector();
  6285. }
  6286. // This allocation belongs to general pool.
  6287. else
  6288. {
  6289. pAllocBlockVector = m_pBlockVectors[memTypeIndex];
  6290. }
  6291. VmaDefragmentator* const pDefragmentator = pAllocBlockVector->EnsureDefragmentator(this, currentFrameIndex);
  6292. VkBool32* const pChanged = (pAllocationsChanged != VMA_NULL) ?
  6293. &pAllocationsChanged[allocIndex] : VMA_NULL;
  6294. pDefragmentator->AddAllocation(hAlloc, pChanged);
  6295. }
  6296. }
  6297. VkResult result = VK_SUCCESS;
  6298. // ======== Main processing.
  6299. VkDeviceSize maxBytesToMove = SIZE_MAX;
  6300. uint32_t maxAllocationsToMove = UINT32_MAX;
  6301. if(pDefragmentationInfo != VMA_NULL)
  6302. {
  6303. maxBytesToMove = pDefragmentationInfo->maxBytesToMove;
  6304. maxAllocationsToMove = pDefragmentationInfo->maxAllocationsToMove;
  6305. }
  6306. // Process standard memory.
  6307. for(uint32_t memTypeIndex = 0;
  6308. (memTypeIndex < GetMemoryTypeCount()) && (result == VK_SUCCESS);
  6309. ++memTypeIndex)
  6310. {
  6311. // Only HOST_VISIBLE memory types can be defragmented.
  6312. if((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
  6313. {
  6314. result = m_pBlockVectors[memTypeIndex]->Defragment(
  6315. pDefragmentationStats,
  6316. maxBytesToMove,
  6317. maxAllocationsToMove);
  6318. }
  6319. }
  6320. // Process custom pools.
  6321. for(size_t poolIndex = 0; (poolIndex < poolCount) && (result == VK_SUCCESS); ++poolIndex)
  6322. {
  6323. result = m_Pools[poolIndex]->GetBlockVector().Defragment(
  6324. pDefragmentationStats,
  6325. maxBytesToMove,
  6326. maxAllocationsToMove);
  6327. }
  6328. // ======== Destroy defragmentators.
  6329. // Process custom pools.
  6330. for(size_t poolIndex = poolCount; poolIndex--; )
  6331. {
  6332. m_Pools[poolIndex]->GetBlockVector().DestroyDefragmentator();
  6333. }
  6334. // Process standard memory.
  6335. for(uint32_t memTypeIndex = GetMemoryTypeCount(); memTypeIndex--; )
  6336. {
  6337. if((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
  6338. {
  6339. m_pBlockVectors[memTypeIndex]->DestroyDefragmentator();
  6340. }
  6341. }
  6342. return result;
  6343. }
  6344. void VmaAllocator_T::GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo)
  6345. {
  6346. if(hAllocation->CanBecomeLost())
  6347. {
  6348. /*
  6349. Warning: This is a carefully designed algorithm.
  6350. Do not modify unless you really know what you're doing :)
  6351. */
  6352. uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load();
  6353. uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex();
  6354. for(;;)
  6355. {
  6356. if(localLastUseFrameIndex == VMA_FRAME_INDEX_LOST)
  6357. {
  6358. pAllocationInfo->memoryType = UINT32_MAX;
  6359. pAllocationInfo->deviceMemory = VK_NULL_HANDLE;
  6360. pAllocationInfo->offset = 0;
  6361. pAllocationInfo->size = hAllocation->GetSize();
  6362. pAllocationInfo->pMappedData = VMA_NULL;
  6363. pAllocationInfo->pUserData = hAllocation->GetUserData();
  6364. return;
  6365. }
  6366. else if(localLastUseFrameIndex == localCurrFrameIndex)
  6367. {
  6368. pAllocationInfo->memoryType = hAllocation->GetMemoryTypeIndex();
  6369. pAllocationInfo->deviceMemory = hAllocation->GetMemory();
  6370. pAllocationInfo->offset = hAllocation->GetOffset();
  6371. pAllocationInfo->size = hAllocation->GetSize();
  6372. pAllocationInfo->pMappedData = VMA_NULL;
  6373. pAllocationInfo->pUserData = hAllocation->GetUserData();
  6374. return;
  6375. }
  6376. else // Last use time earlier than current time.
  6377. {
  6378. if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex))
  6379. {
  6380. localLastUseFrameIndex = localCurrFrameIndex;
  6381. }
  6382. }
  6383. }
  6384. }
  6385. else
  6386. {
  6387. pAllocationInfo->memoryType = hAllocation->GetMemoryTypeIndex();
  6388. pAllocationInfo->deviceMemory = hAllocation->GetMemory();
  6389. pAllocationInfo->offset = hAllocation->GetOffset();
  6390. pAllocationInfo->size = hAllocation->GetSize();
  6391. pAllocationInfo->pMappedData = hAllocation->GetMappedData();
  6392. pAllocationInfo->pUserData = hAllocation->GetUserData();
  6393. }
  6394. }
  6395. VkResult VmaAllocator_T::CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPool* pPool)
  6396. {
  6397. VMA_DEBUG_LOG(" CreatePool: MemoryTypeIndex=%u", pCreateInfo->memoryTypeIndex);
  6398. VmaPoolCreateInfo newCreateInfo = *pCreateInfo;
  6399. if(newCreateInfo.maxBlockCount == 0)
  6400. {
  6401. newCreateInfo.maxBlockCount = SIZE_MAX;
  6402. }
  6403. if(newCreateInfo.blockSize == 0)
  6404. {
  6405. newCreateInfo.blockSize = CalcPreferredBlockSize(newCreateInfo.memoryTypeIndex);
  6406. }
  6407. *pPool = vma_new(this, VmaPool_T)(this, newCreateInfo);
  6408. VkResult res = (*pPool)->m_BlockVector.CreateMinBlocks();
  6409. if(res != VK_SUCCESS)
  6410. {
  6411. vma_delete(this, *pPool);
  6412. *pPool = VMA_NULL;
  6413. return res;
  6414. }
  6415. // Add to m_Pools.
  6416. {
  6417. VmaMutexLock lock(m_PoolsMutex, m_UseMutex);
  6418. VmaVectorInsertSorted<VmaPointerLess>(m_Pools, *pPool);
  6419. }
  6420. return VK_SUCCESS;
  6421. }
  6422. void VmaAllocator_T::DestroyPool(VmaPool pool)
  6423. {
  6424. // Remove from m_Pools.
  6425. {
  6426. VmaMutexLock lock(m_PoolsMutex, m_UseMutex);
  6427. bool success = VmaVectorRemoveSorted<VmaPointerLess>(m_Pools, pool);
  6428. VMA_ASSERT(success && "Pool not found in Allocator.");
  6429. }
  6430. vma_delete(this, pool);
  6431. }
  6432. void VmaAllocator_T::GetPoolStats(VmaPool pool, VmaPoolStats* pPoolStats)
  6433. {
  6434. pool->m_BlockVector.GetPoolStats(pPoolStats);
  6435. }
  6436. void VmaAllocator_T::SetCurrentFrameIndex(uint32_t frameIndex)
  6437. {
  6438. m_CurrentFrameIndex.store(frameIndex);
  6439. }
  6440. void VmaAllocator_T::MakePoolAllocationsLost(
  6441. VmaPool hPool,
  6442. size_t* pLostAllocationCount)
  6443. {
  6444. hPool->m_BlockVector.MakePoolAllocationsLost(
  6445. m_CurrentFrameIndex.load(),
  6446. pLostAllocationCount);
  6447. }
  6448. void VmaAllocator_T::CreateLostAllocation(VmaAllocation* pAllocation)
  6449. {
  6450. *pAllocation = vma_new(this, VmaAllocation_T)(VMA_FRAME_INDEX_LOST, false);
  6451. (*pAllocation)->InitLost();
  6452. }
  6453. VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory)
  6454. {
  6455. const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(pAllocateInfo->memoryTypeIndex);
  6456. VkResult res;
  6457. if(m_HeapSizeLimit[heapIndex] != VK_WHOLE_SIZE)
  6458. {
  6459. VmaMutexLock lock(m_HeapSizeLimitMutex, m_UseMutex);
  6460. if(m_HeapSizeLimit[heapIndex] >= pAllocateInfo->allocationSize)
  6461. {
  6462. res = (*m_VulkanFunctions.vkAllocateMemory)(m_hDevice, pAllocateInfo, GetAllocationCallbacks(), pMemory);
  6463. if(res == VK_SUCCESS)
  6464. {
  6465. m_HeapSizeLimit[heapIndex] -= pAllocateInfo->allocationSize;
  6466. }
  6467. }
  6468. else
  6469. {
  6470. res = VK_ERROR_OUT_OF_DEVICE_MEMORY;
  6471. }
  6472. }
  6473. else
  6474. {
  6475. res = (*m_VulkanFunctions.vkAllocateMemory)(m_hDevice, pAllocateInfo, GetAllocationCallbacks(), pMemory);
  6476. }
  6477. if(res == VK_SUCCESS && m_DeviceMemoryCallbacks.pfnAllocate != VMA_NULL)
  6478. {
  6479. (*m_DeviceMemoryCallbacks.pfnAllocate)(this, pAllocateInfo->memoryTypeIndex, *pMemory, pAllocateInfo->allocationSize);
  6480. }
  6481. return res;
  6482. }
  6483. void VmaAllocator_T::FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, VkDeviceMemory hMemory)
  6484. {
  6485. if(m_DeviceMemoryCallbacks.pfnFree != VMA_NULL)
  6486. {
  6487. (*m_DeviceMemoryCallbacks.pfnFree)(this, memoryType, hMemory, size);
  6488. }
  6489. (*m_VulkanFunctions.vkFreeMemory)(m_hDevice, hMemory, GetAllocationCallbacks());
  6490. const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memoryType);
  6491. if(m_HeapSizeLimit[heapIndex] != VK_WHOLE_SIZE)
  6492. {
  6493. VmaMutexLock lock(m_HeapSizeLimitMutex, m_UseMutex);
  6494. m_HeapSizeLimit[heapIndex] += size;
  6495. }
  6496. }
  6497. VkResult VmaAllocator_T::Map(VmaAllocation hAllocation, void** ppData)
  6498. {
  6499. if(hAllocation->CanBecomeLost())
  6500. {
  6501. return VK_ERROR_MEMORY_MAP_FAILED;
  6502. }
  6503. switch(hAllocation->GetType())
  6504. {
  6505. case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
  6506. {
  6507. VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock();
  6508. char *pBytes = nullptr;
  6509. VkResult res = pBlock->Map(this, (void**)&pBytes);
  6510. if(res == VK_SUCCESS)
  6511. {
  6512. *ppData = pBytes + (ptrdiff_t)hAllocation->GetOffset();
  6513. hAllocation->BlockAllocMap();
  6514. }
  6515. return res;
  6516. }
  6517. case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
  6518. return hAllocation->DedicatedAllocMap(this, ppData);
  6519. default:
  6520. VMA_ASSERT(0);
  6521. return VK_ERROR_MEMORY_MAP_FAILED;
  6522. }
  6523. }
  6524. void VmaAllocator_T::Unmap(VmaAllocation hAllocation)
  6525. {
  6526. switch(hAllocation->GetType())
  6527. {
  6528. case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
  6529. {
  6530. VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock();
  6531. hAllocation->BlockAllocUnmap();
  6532. pBlock->Unmap(this);
  6533. }
  6534. break;
  6535. case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
  6536. hAllocation->DedicatedAllocUnmap(this);
  6537. break;
  6538. default:
  6539. VMA_ASSERT(0);
  6540. }
  6541. }
  6542. void VmaAllocator_T::FreeDedicatedMemory(VmaAllocation allocation)
  6543. {
  6544. VMA_ASSERT(allocation && allocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
  6545. const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex();
  6546. {
  6547. VmaMutexLock lock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
  6548. AllocationVectorType* const pDedicatedAllocations = m_pDedicatedAllocations[memTypeIndex];
  6549. VMA_ASSERT(pDedicatedAllocations);
  6550. bool success = VmaVectorRemoveSorted<VmaPointerLess>(*pDedicatedAllocations, allocation);
  6551. VMA_ASSERT(success);
  6552. }
  6553. VkDeviceMemory hMemory = allocation->GetMemory();
  6554. if(allocation->GetMappedData() != VMA_NULL)
  6555. {
  6556. (*m_VulkanFunctions.vkUnmapMemory)(m_hDevice, hMemory);
  6557. }
  6558. FreeVulkanMemory(memTypeIndex, allocation->GetSize(), hMemory);
  6559. VMA_DEBUG_LOG(" Freed DedicatedMemory MemoryTypeIndex=%u", memTypeIndex);
  6560. }
  6561. #if VMA_STATS_STRING_ENABLED
  6562. void VmaAllocator_T::PrintDetailedMap(VmaJsonWriter& json)
  6563. {
  6564. bool dedicatedAllocationsStarted = false;
  6565. for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
  6566. {
  6567. VmaMutexLock dedicatedAllocationsLock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
  6568. AllocationVectorType* const pDedicatedAllocVector = m_pDedicatedAllocations[memTypeIndex];
  6569. VMA_ASSERT(pDedicatedAllocVector);
  6570. if(pDedicatedAllocVector->empty() == false)
  6571. {
  6572. if(dedicatedAllocationsStarted == false)
  6573. {
  6574. dedicatedAllocationsStarted = true;
  6575. json.WriteString("DedicatedAllocations");
  6576. json.BeginObject();
  6577. }
  6578. json.BeginString("Type ");
  6579. json.ContinueString(memTypeIndex);
  6580. json.EndString();
  6581. json.BeginArray();
  6582. for(size_t i = 0; i < pDedicatedAllocVector->size(); ++i)
  6583. {
  6584. const VmaAllocation hAlloc = (*pDedicatedAllocVector)[i];
  6585. json.BeginObject(true);
  6586. json.WriteString("Type");
  6587. json.WriteString(VMA_SUBALLOCATION_TYPE_NAMES[hAlloc->GetSuballocationType()]);
  6588. json.WriteString("Size");
  6589. json.WriteNumber(hAlloc->GetSize());
  6590. const void* pUserData = hAlloc->GetUserData();
  6591. if(pUserData != VMA_NULL)
  6592. {
  6593. json.WriteString("UserData");
  6594. if(hAlloc->IsUserDataString())
  6595. {
  6596. json.WriteString((const char*)pUserData);
  6597. }
  6598. else
  6599. {
  6600. json.BeginString();
  6601. json.ContinueString_Pointer(pUserData);
  6602. json.EndString();
  6603. }
  6604. }
  6605. json.EndObject();
  6606. }
  6607. json.EndArray();
  6608. }
  6609. }
  6610. if(dedicatedAllocationsStarted)
  6611. {
  6612. json.EndObject();
  6613. }
  6614. {
  6615. bool allocationsStarted = false;
  6616. for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
  6617. {
  6618. if(m_pBlockVectors[memTypeIndex]->IsEmpty() == false)
  6619. {
  6620. if(allocationsStarted == false)
  6621. {
  6622. allocationsStarted = true;
  6623. json.WriteString("DefaultPools");
  6624. json.BeginObject();
  6625. }
  6626. json.BeginString("Type ");
  6627. json.ContinueString(memTypeIndex);
  6628. json.EndString();
  6629. m_pBlockVectors[memTypeIndex]->PrintDetailedMap(json);
  6630. }
  6631. }
  6632. if(allocationsStarted)
  6633. {
  6634. json.EndObject();
  6635. }
  6636. }
  6637. {
  6638. VmaMutexLock lock(m_PoolsMutex, m_UseMutex);
  6639. const size_t poolCount = m_Pools.size();
  6640. if(poolCount > 0)
  6641. {
  6642. json.WriteString("Pools");
  6643. json.BeginArray();
  6644. for(size_t poolIndex = 0; poolIndex < poolCount; ++poolIndex)
  6645. {
  6646. m_Pools[poolIndex]->m_BlockVector.PrintDetailedMap(json);
  6647. }
  6648. json.EndArray();
  6649. }
  6650. }
  6651. }
  6652. #endif // #if VMA_STATS_STRING_ENABLED
  6653. static VkResult AllocateMemoryForImage(
  6654. VmaAllocator allocator,
  6655. VkImage image,
  6656. const VmaAllocationCreateInfo* pAllocationCreateInfo,
  6657. VmaSuballocationType suballocType,
  6658. VmaAllocation* pAllocation)
  6659. {
  6660. VMA_ASSERT(allocator && (image != VK_NULL_HANDLE) && pAllocationCreateInfo && pAllocation);
  6661. VkMemoryRequirements vkMemReq = {};
  6662. bool requiresDedicatedAllocation = false;
  6663. bool prefersDedicatedAllocation = false;
  6664. allocator->GetImageMemoryRequirements(image, vkMemReq,
  6665. requiresDedicatedAllocation, prefersDedicatedAllocation);
  6666. return allocator->AllocateMemory(
  6667. vkMemReq,
  6668. requiresDedicatedAllocation,
  6669. prefersDedicatedAllocation,
  6670. VK_NULL_HANDLE, // dedicatedBuffer
  6671. image, // dedicatedImage
  6672. *pAllocationCreateInfo,
  6673. suballocType,
  6674. pAllocation);
  6675. }
  6676. ////////////////////////////////////////////////////////////////////////////////
  6677. // Public interface
  6678. VkResult vmaCreateAllocator(
  6679. const VmaAllocatorCreateInfo* pCreateInfo,
  6680. VmaAllocator* pAllocator)
  6681. {
  6682. VMA_ASSERT(pCreateInfo && pAllocator);
  6683. VMA_DEBUG_LOG("vmaCreateAllocator");
  6684. *pAllocator = vma_new(pCreateInfo->pAllocationCallbacks, VmaAllocator_T)(pCreateInfo);
  6685. return VK_SUCCESS;
  6686. }
  6687. void vmaDestroyAllocator(
  6688. VmaAllocator allocator)
  6689. {
  6690. if(allocator != VK_NULL_HANDLE)
  6691. {
  6692. VMA_DEBUG_LOG("vmaDestroyAllocator");
  6693. VkAllocationCallbacks allocationCallbacks = allocator->m_AllocationCallbacks;
  6694. vma_delete(&allocationCallbacks, allocator);
  6695. }
  6696. }
  6697. void vmaGetPhysicalDeviceProperties(
  6698. VmaAllocator allocator,
  6699. const VkPhysicalDeviceProperties **ppPhysicalDeviceProperties)
  6700. {
  6701. VMA_ASSERT(allocator && ppPhysicalDeviceProperties);
  6702. *ppPhysicalDeviceProperties = &allocator->m_PhysicalDeviceProperties;
  6703. }
  6704. void vmaGetMemoryProperties(
  6705. VmaAllocator allocator,
  6706. const VkPhysicalDeviceMemoryProperties** ppPhysicalDeviceMemoryProperties)
  6707. {
  6708. VMA_ASSERT(allocator && ppPhysicalDeviceMemoryProperties);
  6709. *ppPhysicalDeviceMemoryProperties = &allocator->m_MemProps;
  6710. }
  6711. void vmaGetMemoryTypeProperties(
  6712. VmaAllocator allocator,
  6713. uint32_t memoryTypeIndex,
  6714. VkMemoryPropertyFlags* pFlags)
  6715. {
  6716. VMA_ASSERT(allocator && pFlags);
  6717. VMA_ASSERT(memoryTypeIndex < allocator->GetMemoryTypeCount());
  6718. *pFlags = allocator->m_MemProps.memoryTypes[memoryTypeIndex].propertyFlags;
  6719. }
  6720. void vmaSetCurrentFrameIndex(
  6721. VmaAllocator allocator,
  6722. uint32_t frameIndex)
  6723. {
  6724. VMA_ASSERT(allocator);
  6725. VMA_ASSERT(frameIndex != VMA_FRAME_INDEX_LOST);
  6726. VMA_DEBUG_GLOBAL_MUTEX_LOCK
  6727. allocator->SetCurrentFrameIndex(frameIndex);
  6728. }
  6729. void vmaCalculateStats(
  6730. VmaAllocator allocator,
  6731. VmaStats* pStats)
  6732. {
  6733. VMA_ASSERT(allocator && pStats);
  6734. VMA_DEBUG_GLOBAL_MUTEX_LOCK
  6735. allocator->CalculateStats(pStats);
  6736. }
  6737. #if VMA_STATS_STRING_ENABLED
  6738. void vmaBuildStatsString(
  6739. VmaAllocator allocator,
  6740. char** ppStatsString,
  6741. VkBool32 detailedMap)
  6742. {
  6743. VMA_ASSERT(allocator && ppStatsString);
  6744. VMA_DEBUG_GLOBAL_MUTEX_LOCK
  6745. VmaStringBuilder sb(allocator);
  6746. {
  6747. VmaJsonWriter json(allocator->GetAllocationCallbacks(), sb);
  6748. json.BeginObject();
  6749. VmaStats stats;
  6750. allocator->CalculateStats(&stats);
  6751. json.WriteString("Total");
  6752. VmaPrintStatInfo(json, stats.total);
  6753. for(uint32_t heapIndex = 0; heapIndex < allocator->GetMemoryHeapCount(); ++heapIndex)
  6754. {
  6755. json.BeginString("Heap ");
  6756. json.ContinueString(heapIndex);
  6757. json.EndString();
  6758. json.BeginObject();
  6759. json.WriteString("Size");
  6760. json.WriteNumber(allocator->m_MemProps.memoryHeaps[heapIndex].size);
  6761. json.WriteString("Flags");
  6762. json.BeginArray(true);
  6763. if((allocator->m_MemProps.memoryHeaps[heapIndex].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0)
  6764. {
  6765. json.WriteString("DEVICE_LOCAL");
  6766. }
  6767. json.EndArray();
  6768. if(stats.memoryHeap[heapIndex].blockCount > 0)
  6769. {
  6770. json.WriteString("Stats");
  6771. VmaPrintStatInfo(json, stats.memoryHeap[heapIndex]);
  6772. }
  6773. for(uint32_t typeIndex = 0; typeIndex < allocator->GetMemoryTypeCount(); ++typeIndex)
  6774. {
  6775. if(allocator->MemoryTypeIndexToHeapIndex(typeIndex) == heapIndex)
  6776. {
  6777. json.BeginString("Type ");
  6778. json.ContinueString(typeIndex);
  6779. json.EndString();
  6780. json.BeginObject();
  6781. json.WriteString("Flags");
  6782. json.BeginArray(true);
  6783. VkMemoryPropertyFlags flags = allocator->m_MemProps.memoryTypes[typeIndex].propertyFlags;
  6784. if((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0)
  6785. {
  6786. json.WriteString("DEVICE_LOCAL");
  6787. }
  6788. if((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
  6789. {
  6790. json.WriteString("HOST_VISIBLE");
  6791. }
  6792. if((flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0)
  6793. {
  6794. json.WriteString("HOST_COHERENT");
  6795. }
  6796. if((flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) != 0)
  6797. {
  6798. json.WriteString("HOST_CACHED");
  6799. }
  6800. if((flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) != 0)
  6801. {
  6802. json.WriteString("LAZILY_ALLOCATED");
  6803. }
  6804. json.EndArray();
  6805. if(stats.memoryType[typeIndex].blockCount > 0)
  6806. {
  6807. json.WriteString("Stats");
  6808. VmaPrintStatInfo(json, stats.memoryType[typeIndex]);
  6809. }
  6810. json.EndObject();
  6811. }
  6812. }
  6813. json.EndObject();
  6814. }
  6815. if(detailedMap == VK_TRUE)
  6816. {
  6817. allocator->PrintDetailedMap(json);
  6818. }
  6819. json.EndObject();
  6820. }
  6821. const size_t len = sb.GetLength();
  6822. char* const pChars = vma_new_array(allocator, char, len + 1);
  6823. if(len > 0)
  6824. {
  6825. memcpy(pChars, sb.GetData(), len);
  6826. }
  6827. pChars[len] = '\0';
  6828. *ppStatsString = pChars;
  6829. }
  6830. void vmaFreeStatsString(
  6831. VmaAllocator allocator,
  6832. char* pStatsString)
  6833. {
  6834. if(pStatsString != VMA_NULL)
  6835. {
  6836. VMA_ASSERT(allocator);
  6837. size_t len = strlen(pStatsString);
  6838. vma_delete_array(allocator, pStatsString, len + 1);
  6839. }
  6840. }
  6841. #endif // #if VMA_STATS_STRING_ENABLED
  6842. /*
  6843. This function is not protected by any mutex because it just reads immutable data.
  6844. */
  6845. VkResult vmaFindMemoryTypeIndex(
  6846. VmaAllocator allocator,
  6847. uint32_t memoryTypeBits,
  6848. const VmaAllocationCreateInfo* pAllocationCreateInfo,
  6849. uint32_t* pMemoryTypeIndex)
  6850. {
  6851. VMA_ASSERT(allocator != VK_NULL_HANDLE);
  6852. VMA_ASSERT(pAllocationCreateInfo != VMA_NULL);
  6853. VMA_ASSERT(pMemoryTypeIndex != VMA_NULL);
  6854. if(pAllocationCreateInfo->memoryTypeBits != 0)
  6855. {
  6856. memoryTypeBits &= pAllocationCreateInfo->memoryTypeBits;
  6857. }
  6858. uint32_t requiredFlags = pAllocationCreateInfo->requiredFlags;
  6859. uint32_t preferredFlags = pAllocationCreateInfo->preferredFlags;
  6860. // Convert usage to requiredFlags and preferredFlags.
  6861. switch(pAllocationCreateInfo->usage)
  6862. {
  6863. case VMA_MEMORY_USAGE_UNKNOWN:
  6864. break;
  6865. case VMA_MEMORY_USAGE_GPU_ONLY:
  6866. preferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
  6867. break;
  6868. case VMA_MEMORY_USAGE_CPU_ONLY:
  6869. requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
  6870. break;
  6871. case VMA_MEMORY_USAGE_CPU_TO_GPU:
  6872. requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
  6873. preferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
  6874. break;
  6875. case VMA_MEMORY_USAGE_GPU_TO_CPU:
  6876. requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
  6877. preferredFlags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
  6878. break;
  6879. default:
  6880. break;
  6881. }
  6882. *pMemoryTypeIndex = UINT32_MAX;
  6883. uint32_t minCost = UINT32_MAX;
  6884. for(uint32_t memTypeIndex = 0, memTypeBit = 1;
  6885. memTypeIndex < allocator->GetMemoryTypeCount();
  6886. ++memTypeIndex, memTypeBit <<= 1)
  6887. {
  6888. // This memory type is acceptable according to memoryTypeBits bitmask.
  6889. if((memTypeBit & memoryTypeBits) != 0)
  6890. {
  6891. const VkMemoryPropertyFlags currFlags =
  6892. allocator->m_MemProps.memoryTypes[memTypeIndex].propertyFlags;
  6893. // This memory type contains requiredFlags.
  6894. if((requiredFlags & ~currFlags) == 0)
  6895. {
  6896. // Calculate cost as number of bits from preferredFlags not present in this memory type.
  6897. uint32_t currCost = VmaCountBitsSet(preferredFlags & ~currFlags);
  6898. // Remember memory type with lowest cost.
  6899. if(currCost < minCost)
  6900. {
  6901. *pMemoryTypeIndex = memTypeIndex;
  6902. if(currCost == 0)
  6903. {
  6904. return VK_SUCCESS;
  6905. }
  6906. minCost = currCost;
  6907. }
  6908. }
  6909. }
  6910. }
  6911. return (*pMemoryTypeIndex != UINT32_MAX) ? VK_SUCCESS : VK_ERROR_FEATURE_NOT_PRESENT;
  6912. }
  6913. VkResult vmaCreatePool(
  6914. VmaAllocator allocator,
  6915. const VmaPoolCreateInfo* pCreateInfo,
  6916. VmaPool* pPool)
  6917. {
  6918. VMA_ASSERT(allocator && pCreateInfo && pPool);
  6919. VMA_DEBUG_LOG("vmaCreatePool");
  6920. VMA_DEBUG_GLOBAL_MUTEX_LOCK
  6921. return allocator->CreatePool(pCreateInfo, pPool);
  6922. }
  6923. void vmaDestroyPool(
  6924. VmaAllocator allocator,
  6925. VmaPool pool)
  6926. {
  6927. VMA_ASSERT(allocator);
  6928. if(pool == VK_NULL_HANDLE)
  6929. {
  6930. return;
  6931. }
  6932. VMA_DEBUG_LOG("vmaDestroyPool");
  6933. VMA_DEBUG_GLOBAL_MUTEX_LOCK
  6934. allocator->DestroyPool(pool);
  6935. }
  6936. void vmaGetPoolStats(
  6937. VmaAllocator allocator,
  6938. VmaPool pool,
  6939. VmaPoolStats* pPoolStats)
  6940. {
  6941. VMA_ASSERT(allocator && pool && pPoolStats);
  6942. VMA_DEBUG_GLOBAL_MUTEX_LOCK
  6943. allocator->GetPoolStats(pool, pPoolStats);
  6944. }
  6945. void vmaMakePoolAllocationsLost(
  6946. VmaAllocator allocator,
  6947. VmaPool pool,
  6948. size_t* pLostAllocationCount)
  6949. {
  6950. VMA_ASSERT(allocator && pool);
  6951. VMA_DEBUG_GLOBAL_MUTEX_LOCK
  6952. allocator->MakePoolAllocationsLost(pool, pLostAllocationCount);
  6953. }
  6954. VkResult vmaAllocateMemory(
  6955. VmaAllocator allocator,
  6956. const VkMemoryRequirements* pVkMemoryRequirements,
  6957. const VmaAllocationCreateInfo* pCreateInfo,
  6958. VmaAllocation* pAllocation,
  6959. VmaAllocationInfo* pAllocationInfo)
  6960. {
  6961. VMA_ASSERT(allocator && pVkMemoryRequirements && pCreateInfo && pAllocation);
  6962. VMA_DEBUG_LOG("vmaAllocateMemory");
  6963. VMA_DEBUG_GLOBAL_MUTEX_LOCK
  6964. VkResult result = allocator->AllocateMemory(
  6965. *pVkMemoryRequirements,
  6966. false, // requiresDedicatedAllocation
  6967. false, // prefersDedicatedAllocation
  6968. VK_NULL_HANDLE, // dedicatedBuffer
  6969. VK_NULL_HANDLE, // dedicatedImage
  6970. *pCreateInfo,
  6971. VMA_SUBALLOCATION_TYPE_UNKNOWN,
  6972. pAllocation);
  6973. if(pAllocationInfo && result == VK_SUCCESS)
  6974. {
  6975. allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
  6976. }
  6977. return result;
  6978. }
  6979. VkResult vmaAllocateMemoryForBuffer(
  6980. VmaAllocator allocator,
  6981. VkBuffer buffer,
  6982. const VmaAllocationCreateInfo* pCreateInfo,
  6983. VmaAllocation* pAllocation,
  6984. VmaAllocationInfo* pAllocationInfo)
  6985. {
  6986. VMA_ASSERT(allocator && buffer != VK_NULL_HANDLE && pCreateInfo && pAllocation);
  6987. VMA_DEBUG_LOG("vmaAllocateMemoryForBuffer");
  6988. VMA_DEBUG_GLOBAL_MUTEX_LOCK
  6989. VkMemoryRequirements vkMemReq = {};
  6990. bool requiresDedicatedAllocation = false;
  6991. bool prefersDedicatedAllocation = false;
  6992. allocator->GetBufferMemoryRequirements(buffer, vkMemReq,
  6993. requiresDedicatedAllocation,
  6994. prefersDedicatedAllocation);
  6995. VkResult result = allocator->AllocateMemory(
  6996. vkMemReq,
  6997. requiresDedicatedAllocation,
  6998. prefersDedicatedAllocation,
  6999. buffer, // dedicatedBuffer
  7000. VK_NULL_HANDLE, // dedicatedImage
  7001. *pCreateInfo,
  7002. VMA_SUBALLOCATION_TYPE_BUFFER,
  7003. pAllocation);
  7004. if(pAllocationInfo && result == VK_SUCCESS)
  7005. {
  7006. allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
  7007. }
  7008. return result;
  7009. }
  7010. VkResult vmaAllocateMemoryForImage(
  7011. VmaAllocator allocator,
  7012. VkImage image,
  7013. const VmaAllocationCreateInfo* pCreateInfo,
  7014. VmaAllocation* pAllocation,
  7015. VmaAllocationInfo* pAllocationInfo)
  7016. {
  7017. VMA_ASSERT(allocator && image != VK_NULL_HANDLE && pCreateInfo && pAllocation);
  7018. VMA_DEBUG_LOG("vmaAllocateMemoryForImage");
  7019. VMA_DEBUG_GLOBAL_MUTEX_LOCK
  7020. VkResult result = AllocateMemoryForImage(
  7021. allocator,
  7022. image,
  7023. pCreateInfo,
  7024. VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN,
  7025. pAllocation);
  7026. if(pAllocationInfo && result == VK_SUCCESS)
  7027. {
  7028. allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
  7029. }
  7030. return result;
  7031. }
  7032. void vmaFreeMemory(
  7033. VmaAllocator allocator,
  7034. VmaAllocation allocation)
  7035. {
  7036. VMA_ASSERT(allocator && allocation);
  7037. VMA_DEBUG_LOG("vmaFreeMemory");
  7038. VMA_DEBUG_GLOBAL_MUTEX_LOCK
  7039. allocator->FreeMemory(allocation);
  7040. }
  7041. void vmaGetAllocationInfo(
  7042. VmaAllocator allocator,
  7043. VmaAllocation allocation,
  7044. VmaAllocationInfo* pAllocationInfo)
  7045. {
  7046. VMA_ASSERT(allocator && allocation && pAllocationInfo);
  7047. VMA_DEBUG_GLOBAL_MUTEX_LOCK
  7048. allocator->GetAllocationInfo(allocation, pAllocationInfo);
  7049. }
  7050. void vmaSetAllocationUserData(
  7051. VmaAllocator allocator,
  7052. VmaAllocation allocation,
  7053. void* pUserData)
  7054. {
  7055. VMA_ASSERT(allocator && allocation);
  7056. VMA_DEBUG_GLOBAL_MUTEX_LOCK
  7057. allocation->SetUserData(allocator, pUserData);
  7058. }
  7059. void vmaCreateLostAllocation(
  7060. VmaAllocator allocator,
  7061. VmaAllocation* pAllocation)
  7062. {
  7063. VMA_ASSERT(allocator && pAllocation);
  7064. VMA_DEBUG_GLOBAL_MUTEX_LOCK;
  7065. allocator->CreateLostAllocation(pAllocation);
  7066. }
  7067. VkResult vmaMapMemory(
  7068. VmaAllocator allocator,
  7069. VmaAllocation allocation,
  7070. void** ppData)
  7071. {
  7072. VMA_ASSERT(allocator && allocation && ppData);
  7073. VMA_DEBUG_GLOBAL_MUTEX_LOCK
  7074. return allocator->Map(allocation, ppData);
  7075. }
  7076. void vmaUnmapMemory(
  7077. VmaAllocator allocator,
  7078. VmaAllocation allocation)
  7079. {
  7080. VMA_ASSERT(allocator && allocation);
  7081. VMA_DEBUG_GLOBAL_MUTEX_LOCK
  7082. allocator->Unmap(allocation);
  7083. }
  7084. VkResult vmaDefragment(
  7085. VmaAllocator allocator,
  7086. VmaAllocation* pAllocations,
  7087. size_t allocationCount,
  7088. VkBool32* pAllocationsChanged,
  7089. const VmaDefragmentationInfo *pDefragmentationInfo,
  7090. VmaDefragmentationStats* pDefragmentationStats)
  7091. {
  7092. VMA_ASSERT(allocator && pAllocations);
  7093. VMA_DEBUG_LOG("vmaDefragment");
  7094. VMA_DEBUG_GLOBAL_MUTEX_LOCK
  7095. return allocator->Defragment(pAllocations, allocationCount, pAllocationsChanged, pDefragmentationInfo, pDefragmentationStats);
  7096. }
  7097. VkResult vmaCreateBuffer(
  7098. VmaAllocator allocator,
  7099. const VkBufferCreateInfo* pBufferCreateInfo,
  7100. const VmaAllocationCreateInfo* pAllocationCreateInfo,
  7101. VkBuffer* pBuffer,
  7102. VmaAllocation* pAllocation,
  7103. VmaAllocationInfo* pAllocationInfo)
  7104. {
  7105. VMA_ASSERT(allocator && pBufferCreateInfo && pAllocationCreateInfo && pBuffer && pAllocation);
  7106. VMA_DEBUG_LOG("vmaCreateBuffer");
  7107. VMA_DEBUG_GLOBAL_MUTEX_LOCK
  7108. *pBuffer = VK_NULL_HANDLE;
  7109. *pAllocation = VK_NULL_HANDLE;
  7110. // 1. Create VkBuffer.
  7111. VkResult res = (*allocator->GetVulkanFunctions().vkCreateBuffer)(
  7112. allocator->m_hDevice,
  7113. pBufferCreateInfo,
  7114. allocator->GetAllocationCallbacks(),
  7115. pBuffer);
  7116. if(res >= 0)
  7117. {
  7118. // 2. vkGetBufferMemoryRequirements.
  7119. VkMemoryRequirements vkMemReq = {};
  7120. bool requiresDedicatedAllocation = false;
  7121. bool prefersDedicatedAllocation = false;
  7122. allocator->GetBufferMemoryRequirements(*pBuffer, vkMemReq,
  7123. requiresDedicatedAllocation, prefersDedicatedAllocation);
  7124. // Make sure alignment requirements for specific buffer usages reported
  7125. // in Physical Device Properties are included in alignment reported by memory requirements.
  7126. if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT) != 0)
  7127. {
  7128. VMA_ASSERT(vkMemReq.alignment %
  7129. allocator->m_PhysicalDeviceProperties.limits.minTexelBufferOffsetAlignment == 0);
  7130. }
  7131. if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) != 0)
  7132. {
  7133. VMA_ASSERT(vkMemReq.alignment %
  7134. allocator->m_PhysicalDeviceProperties.limits.minUniformBufferOffsetAlignment == 0);
  7135. }
  7136. if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) != 0)
  7137. {
  7138. VMA_ASSERT(vkMemReq.alignment %
  7139. allocator->m_PhysicalDeviceProperties.limits.minStorageBufferOffsetAlignment == 0);
  7140. }
  7141. // 3. Allocate memory using allocator.
  7142. res = allocator->AllocateMemory(
  7143. vkMemReq,
  7144. requiresDedicatedAllocation,
  7145. prefersDedicatedAllocation,
  7146. *pBuffer, // dedicatedBuffer
  7147. VK_NULL_HANDLE, // dedicatedImage
  7148. *pAllocationCreateInfo,
  7149. VMA_SUBALLOCATION_TYPE_BUFFER,
  7150. pAllocation);
  7151. if(res >= 0)
  7152. {
  7153. // 3. Bind buffer with memory.
  7154. res = (*allocator->GetVulkanFunctions().vkBindBufferMemory)(
  7155. allocator->m_hDevice,
  7156. *pBuffer,
  7157. (*pAllocation)->GetMemory(),
  7158. (*pAllocation)->GetOffset());
  7159. if(res >= 0)
  7160. {
  7161. // All steps succeeded.
  7162. if(pAllocationInfo != VMA_NULL)
  7163. {
  7164. allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
  7165. }
  7166. return VK_SUCCESS;
  7167. }
  7168. allocator->FreeMemory(*pAllocation);
  7169. *pAllocation = VK_NULL_HANDLE;
  7170. (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks());
  7171. *pBuffer = VK_NULL_HANDLE;
  7172. return res;
  7173. }
  7174. (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks());
  7175. *pBuffer = VK_NULL_HANDLE;
  7176. return res;
  7177. }
  7178. return res;
  7179. }
  7180. void vmaDestroyBuffer(
  7181. VmaAllocator allocator,
  7182. VkBuffer buffer,
  7183. VmaAllocation allocation)
  7184. {
  7185. if(buffer != VK_NULL_HANDLE)
  7186. {
  7187. VMA_ASSERT(allocator);
  7188. VMA_DEBUG_LOG("vmaDestroyBuffer");
  7189. VMA_DEBUG_GLOBAL_MUTEX_LOCK
  7190. (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, buffer, allocator->GetAllocationCallbacks());
  7191. allocator->FreeMemory(allocation);
  7192. }
  7193. }
  7194. VkResult vmaCreateImage(
  7195. VmaAllocator allocator,
  7196. const VkImageCreateInfo* pImageCreateInfo,
  7197. const VmaAllocationCreateInfo* pAllocationCreateInfo,
  7198. VkImage* pImage,
  7199. VmaAllocation* pAllocation,
  7200. VmaAllocationInfo* pAllocationInfo)
  7201. {
  7202. VMA_ASSERT(allocator && pImageCreateInfo && pAllocationCreateInfo && pImage && pAllocation);
  7203. VMA_DEBUG_LOG("vmaCreateImage");
  7204. VMA_DEBUG_GLOBAL_MUTEX_LOCK
  7205. *pImage = VK_NULL_HANDLE;
  7206. *pAllocation = VK_NULL_HANDLE;
  7207. // 1. Create VkImage.
  7208. VkResult res = (*allocator->GetVulkanFunctions().vkCreateImage)(
  7209. allocator->m_hDevice,
  7210. pImageCreateInfo,
  7211. allocator->GetAllocationCallbacks(),
  7212. pImage);
  7213. if(res >= 0)
  7214. {
  7215. VmaSuballocationType suballocType = pImageCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL ?
  7216. VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL :
  7217. VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR;
  7218. // 2. Allocate memory using allocator.
  7219. res = AllocateMemoryForImage(allocator, *pImage, pAllocationCreateInfo, suballocType, pAllocation);
  7220. if(res >= 0)
  7221. {
  7222. // 3. Bind image with memory.
  7223. res = (*allocator->GetVulkanFunctions().vkBindImageMemory)(
  7224. allocator->m_hDevice,
  7225. *pImage,
  7226. (*pAllocation)->GetMemory(),
  7227. (*pAllocation)->GetOffset());
  7228. if(res >= 0)
  7229. {
  7230. // All steps succeeded.
  7231. if(pAllocationInfo != VMA_NULL)
  7232. {
  7233. allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
  7234. }
  7235. return VK_SUCCESS;
  7236. }
  7237. allocator->FreeMemory(*pAllocation);
  7238. *pAllocation = VK_NULL_HANDLE;
  7239. (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks());
  7240. *pImage = VK_NULL_HANDLE;
  7241. return res;
  7242. }
  7243. (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks());
  7244. *pImage = VK_NULL_HANDLE;
  7245. return res;
  7246. }
  7247. return res;
  7248. }
  7249. void vmaDestroyImage(
  7250. VmaAllocator allocator,
  7251. VkImage image,
  7252. VmaAllocation allocation)
  7253. {
  7254. if(image != VK_NULL_HANDLE)
  7255. {
  7256. VMA_ASSERT(allocator);
  7257. VMA_DEBUG_LOG("vmaDestroyImage");
  7258. VMA_DEBUG_GLOBAL_MUTEX_LOCK
  7259. (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, image, allocator->GetAllocationCallbacks());
  7260. allocator->FreeMemory(allocation);
  7261. }
  7262. }
  7263. #endif // #ifdef VMA_IMPLEMENTATION