D3D12MemAlloc.cpp 340 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562
  1. //
  2. // Copyright (c) 2019-2022 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. #include "D3D12MemAlloc.h"
  23. #include <combaseapi.h>
  24. #include <mutex>
  25. #include <algorithm>
  26. #include <utility>
  27. #include <cstdlib>
  28. #include <cstdint>
  29. #include <malloc.h> // for _aligned_malloc, _aligned_free
  30. #ifndef _WIN32
  31. #include <shared_mutex>
  32. #endif
  33. #if !defined(_MSC_VER)
  34. #include <guiddef.h>
  35. #include <dxguids.h>
  36. #endif
  37. ////////////////////////////////////////////////////////////////////////////////
  38. ////////////////////////////////////////////////////////////////////////////////
  39. //
  40. // Configuration Begin
  41. //
  42. ////////////////////////////////////////////////////////////////////////////////
  43. ////////////////////////////////////////////////////////////////////////////////
  44. #ifndef _D3D12MA_CONFIGURATION
  45. #ifdef _WIN32
  46. #if !defined(WINVER) || WINVER < 0x0600
  47. #error Required at least WinAPI version supporting: client = Windows Vista, server = Windows Server 2008.
  48. #endif
  49. #endif
  50. #ifndef D3D12MA_SORT
  51. #define D3D12MA_SORT(beg, end, cmp) std::sort(beg, end, cmp)
  52. #endif
  53. #ifndef D3D12MA_D3D12_HEADERS_ALREADY_INCLUDED
  54. #include <dxgi.h>
  55. #if D3D12MA_DXGI_1_4
  56. #include <dxgi1_4.h>
  57. #endif
  58. #endif
  59. #ifndef D3D12MA_ASSERT
  60. #include <cassert>
  61. #define D3D12MA_ASSERT(cond) assert(cond)
  62. #endif
  63. // Assert that will be called very often, like inside data structures e.g. operator[].
  64. // Making it non-empty can make program slow.
  65. #ifndef D3D12MA_HEAVY_ASSERT
  66. #ifdef _DEBUG
  67. #define D3D12MA_HEAVY_ASSERT(expr) //D3D12MA_ASSERT(expr)
  68. #else
  69. #define D3D12MA_HEAVY_ASSERT(expr)
  70. #endif
  71. #endif
  72. #ifndef D3D12MA_DEBUG_ALIGNMENT
  73. /*
  74. Minimum alignment of all allocations, in bytes.
  75. Set to more than 1 for debugging purposes only. Must be power of two.
  76. */
  77. #define D3D12MA_DEBUG_ALIGNMENT (1)
  78. #endif
  79. #ifndef D3D12MA_DEBUG_MARGIN
  80. // Minimum margin before and after every allocation, in bytes.
  81. // Set nonzero for debugging purposes only.
  82. #define D3D12MA_DEBUG_MARGIN (0)
  83. #endif
  84. #ifndef D3D12MA_DEBUG_GLOBAL_MUTEX
  85. /*
  86. Set this to 1 for debugging purposes only, to enable single mutex protecting all
  87. entry calls to the library. Can be useful for debugging multithreading issues.
  88. */
  89. #define D3D12MA_DEBUG_GLOBAL_MUTEX (0)
  90. #endif
  91. /*
  92. Define this macro for debugging purposes only to force specific D3D12_RESOURCE_HEAP_TIER,
  93. especially to test compatibility with D3D12_RESOURCE_HEAP_TIER_1 on modern GPUs.
  94. */
  95. //#define D3D12MA_FORCE_RESOURCE_HEAP_TIER D3D12_RESOURCE_HEAP_TIER_1
  96. #ifndef D3D12MA_DEFAULT_BLOCK_SIZE
  97. /// Default size of a block allocated as single ID3D12Heap.
  98. #define D3D12MA_DEFAULT_BLOCK_SIZE (64ull * 1024 * 1024)
  99. #endif
  100. #ifndef D3D12MA_DEBUG_LOG
  101. #define D3D12MA_DEBUG_LOG(format, ...)
  102. /*
  103. #define D3D12MA_DEBUG_LOG(format, ...) do { \
  104. wprintf(format, __VA_ARGS__); \
  105. wprintf(L"\n"); \
  106. } while(false)
  107. */
  108. #endif
  109. #endif // _D3D12MA_CONFIGURATION
  110. ////////////////////////////////////////////////////////////////////////////////
  111. ////////////////////////////////////////////////////////////////////////////////
  112. //
  113. // Configuration End
  114. //
  115. ////////////////////////////////////////////////////////////////////////////////
  116. ////////////////////////////////////////////////////////////////////////////////
  117. #define D3D12MA_IID_PPV_ARGS(ppType) __uuidof(**(ppType)), reinterpret_cast<void**>(ppType)
  118. #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  119. #define D3D12MA_CREATE_NOT_ZEROED_AVAILABLE 1
  120. #endif
  121. namespace D3D12MA
  122. {
  123. static constexpr UINT HEAP_TYPE_COUNT = 4;
  124. static constexpr UINT STANDARD_HEAP_TYPE_COUNT = 3; // Only DEFAULT, UPLOAD, READBACK.
  125. static constexpr UINT DEFAULT_POOL_MAX_COUNT = 9;
  126. static const UINT NEW_BLOCK_SIZE_SHIFT_MAX = 3;
  127. // Minimum size of a free suballocation to register it in the free suballocation collection.
  128. static const UINT64 MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER = 16;
  129. static const WCHAR* const HeapTypeNames[] =
  130. {
  131. L"DEFAULT",
  132. L"UPLOAD",
  133. L"READBACK",
  134. L"CUSTOM",
  135. };
  136. static const D3D12_HEAP_FLAGS RESOURCE_CLASS_HEAP_FLAGS =
  137. D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES | D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
  138. static const D3D12_RESIDENCY_PRIORITY D3D12_RESIDENCY_PRIORITY_NONE = D3D12_RESIDENCY_PRIORITY(0);
  139. #ifndef _D3D12MA_ENUM_DECLARATIONS
  140. // Local copy of this enum, as it is provided only by <dxgi1_4.h>, so it may not be available.
  141. enum DXGI_MEMORY_SEGMENT_GROUP_COPY
  142. {
  143. DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY = 0,
  144. DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY = 1,
  145. DXGI_MEMORY_SEGMENT_GROUP_COUNT
  146. };
  147. enum class ResourceClass
  148. {
  149. Unknown, Buffer, Non_RT_DS_Texture, RT_DS_Texture
  150. };
  151. enum SuballocationType
  152. {
  153. SUBALLOCATION_TYPE_FREE = 0,
  154. SUBALLOCATION_TYPE_ALLOCATION = 1,
  155. };
  156. #endif // _D3D12MA_ENUM_DECLARATIONS
  157. #ifndef _D3D12MA_FUNCTIONS
  158. static void* DefaultAllocate(size_t Size, size_t Alignment, void* /*pPrivateData*/)
  159. {
  160. #ifdef _WIN32
  161. return _aligned_malloc(Size, Alignment);
  162. #else
  163. return aligned_alloc(Alignment, Size);
  164. #endif
  165. }
  166. static void DefaultFree(void* pMemory, void* /*pPrivateData*/)
  167. {
  168. #ifdef _WIN32
  169. return _aligned_free(pMemory);
  170. #else
  171. return free(pMemory);
  172. #endif
  173. }
  174. static void* Malloc(const ALLOCATION_CALLBACKS& allocs, size_t size, size_t alignment)
  175. {
  176. void* const result = (*allocs.pAllocate)(size, alignment, allocs.pPrivateData);
  177. D3D12MA_ASSERT(result);
  178. return result;
  179. }
  180. static void Free(const ALLOCATION_CALLBACKS& allocs, void* memory)
  181. {
  182. (*allocs.pFree)(memory, allocs.pPrivateData);
  183. }
  184. template<typename T>
  185. static T* Allocate(const ALLOCATION_CALLBACKS& allocs)
  186. {
  187. return (T*)Malloc(allocs, sizeof(T), __alignof(T));
  188. }
  189. template<typename T>
  190. static T* AllocateArray(const ALLOCATION_CALLBACKS& allocs, size_t count)
  191. {
  192. return (T*)Malloc(allocs, sizeof(T) * count, __alignof(T));
  193. }
  194. #define D3D12MA_NEW(allocs, type) new(D3D12MA::Allocate<type>(allocs))(type)
  195. #define D3D12MA_NEW_ARRAY(allocs, type, count) new(D3D12MA::AllocateArray<type>((allocs), (count)))(type)
  196. template<typename T>
  197. void D3D12MA_DELETE(const ALLOCATION_CALLBACKS& allocs, T* memory)
  198. {
  199. if (memory)
  200. {
  201. memory->~T();
  202. Free(allocs, memory);
  203. }
  204. }
  205. template<typename T>
  206. void D3D12MA_DELETE_ARRAY(const ALLOCATION_CALLBACKS& allocs, T* memory, size_t count)
  207. {
  208. if (memory)
  209. {
  210. for (size_t i = count; i--; )
  211. {
  212. memory[i].~T();
  213. }
  214. Free(allocs, memory);
  215. }
  216. }
  217. static void SetupAllocationCallbacks(ALLOCATION_CALLBACKS& outAllocs, const ALLOCATION_CALLBACKS* allocationCallbacks)
  218. {
  219. if (allocationCallbacks)
  220. {
  221. outAllocs = *allocationCallbacks;
  222. D3D12MA_ASSERT(outAllocs.pAllocate != NULL && outAllocs.pFree != NULL);
  223. }
  224. else
  225. {
  226. outAllocs.pAllocate = &DefaultAllocate;
  227. outAllocs.pFree = &DefaultFree;
  228. outAllocs.pPrivateData = NULL;
  229. }
  230. }
  231. #define SAFE_RELEASE(ptr) do { if(ptr) { (ptr)->Release(); (ptr) = NULL; } } while(false)
  232. #define D3D12MA_VALIDATE(cond) do { if(!(cond)) { \
  233. D3D12MA_ASSERT(0 && "Validation failed: " #cond); \
  234. return false; \
  235. } } while(false)
  236. template<typename T>
  237. static T D3D12MA_MIN(const T& a, const T& b) { return a <= b ? a : b; }
  238. template<typename T>
  239. static T D3D12MA_MAX(const T& a, const T& b) { return a <= b ? b : a; }
  240. template<typename T>
  241. static void D3D12MA_SWAP(T& a, T& b) { T tmp = a; a = b; b = tmp; }
  242. // Scans integer for index of first nonzero bit from the Least Significant Bit (LSB). If mask is 0 then returns UINT8_MAX
  243. static UINT8 BitScanLSB(UINT64 mask)
  244. {
  245. #if defined(_MSC_VER) && defined(_WIN64)
  246. unsigned long pos;
  247. if (_BitScanForward64(&pos, mask))
  248. return static_cast<UINT8>(pos);
  249. return UINT8_MAX;
  250. #elif defined __GNUC__ || defined __clang__
  251. return static_cast<UINT8>(__builtin_ffsll(mask)) - 1U;
  252. #else
  253. UINT8 pos = 0;
  254. UINT64 bit = 1;
  255. do
  256. {
  257. if (mask & bit)
  258. return pos;
  259. bit <<= 1;
  260. } while (pos++ < 63);
  261. return UINT8_MAX;
  262. #endif
  263. }
  264. // Scans integer for index of first nonzero bit from the Least Significant Bit (LSB). If mask is 0 then returns UINT8_MAX
  265. static UINT8 BitScanLSB(UINT32 mask)
  266. {
  267. #ifdef _MSC_VER
  268. unsigned long pos;
  269. if (_BitScanForward(&pos, mask))
  270. return static_cast<UINT8>(pos);
  271. return UINT8_MAX;
  272. #elif defined __GNUC__ || defined __clang__
  273. return static_cast<UINT8>(__builtin_ffs(mask)) - 1U;
  274. #else
  275. UINT8 pos = 0;
  276. UINT32 bit = 1;
  277. do
  278. {
  279. if (mask & bit)
  280. return pos;
  281. bit <<= 1;
  282. } while (pos++ < 31);
  283. return UINT8_MAX;
  284. #endif
  285. }
  286. // Scans integer for index of first nonzero bit from the Most Significant Bit (MSB). If mask is 0 then returns UINT8_MAX
  287. static UINT8 BitScanMSB(UINT64 mask)
  288. {
  289. #if defined(_MSC_VER) && defined(_WIN64)
  290. unsigned long pos;
  291. if (_BitScanReverse64(&pos, mask))
  292. return static_cast<UINT8>(pos);
  293. #elif defined __GNUC__ || defined __clang__
  294. if (mask)
  295. return 63 - static_cast<UINT8>(__builtin_clzll(mask));
  296. #else
  297. UINT8 pos = 63;
  298. UINT64 bit = 1ULL << 63;
  299. do
  300. {
  301. if (mask & bit)
  302. return pos;
  303. bit >>= 1;
  304. } while (pos-- > 0);
  305. #endif
  306. return UINT8_MAX;
  307. }
  308. // Scans integer for index of first nonzero bit from the Most Significant Bit (MSB). If mask is 0 then returns UINT8_MAX
  309. static UINT8 BitScanMSB(UINT32 mask)
  310. {
  311. #ifdef _MSC_VER
  312. unsigned long pos;
  313. if (_BitScanReverse(&pos, mask))
  314. return static_cast<UINT8>(pos);
  315. #elif defined __GNUC__ || defined __clang__
  316. if (mask)
  317. return 31 - static_cast<UINT8>(__builtin_clz(mask));
  318. #else
  319. UINT8 pos = 31;
  320. UINT32 bit = 1UL << 31;
  321. do
  322. {
  323. if (mask & bit)
  324. return pos;
  325. bit >>= 1;
  326. } while (pos-- > 0);
  327. #endif
  328. return UINT8_MAX;
  329. }
  330. /*
  331. Returns true if given number is a power of two.
  332. T must be unsigned integer number or signed integer but always nonnegative.
  333. For 0 returns true.
  334. */
  335. template <typename T>
  336. static bool IsPow2(T x) { return (x & (x - 1)) == 0; }
  337. // Aligns given value up to nearest multiply of align value. For example: AlignUp(11, 8) = 16.
  338. // Use types like UINT, uint64_t as T.
  339. template <typename T>
  340. static T AlignUp(T val, T alignment)
  341. {
  342. D3D12MA_HEAVY_ASSERT(IsPow2(alignment));
  343. return (val + alignment - 1) & ~(alignment - 1);
  344. }
  345. // Aligns given value down to nearest multiply of align value. For example: AlignUp(11, 8) = 8.
  346. // Use types like UINT, uint64_t as T.
  347. template <typename T>
  348. static T AlignDown(T val, T alignment)
  349. {
  350. D3D12MA_HEAVY_ASSERT(IsPow2(alignment));
  351. return val & ~(alignment - 1);
  352. }
  353. // Division with mathematical rounding to nearest number.
  354. template <typename T>
  355. static T RoundDiv(T x, T y) { return (x + (y / (T)2)) / y; }
  356. template <typename T>
  357. static T DivideRoundingUp(T x, T y) { return (x + y - 1) / y; }
  358. static WCHAR HexDigitToChar(UINT8 digit)
  359. {
  360. if(digit < 10)
  361. return L'0' + digit;
  362. else
  363. return L'A' + (digit - 10);
  364. }
  365. /*
  366. Performs binary search and returns iterator to first element that is greater or
  367. equal to `key`, according to comparison `cmp`.
  368. Cmp should return true if first argument is less than second argument.
  369. Returned value is the found element, if present in the collection or place where
  370. new element with value (key) should be inserted.
  371. */
  372. template <typename CmpLess, typename IterT, typename KeyT>
  373. static IterT BinaryFindFirstNotLess(IterT beg, IterT end, const KeyT& key, const CmpLess& cmp)
  374. {
  375. size_t down = 0, up = (end - beg);
  376. while (down < up)
  377. {
  378. const size_t mid = (down + up) / 2;
  379. if (cmp(*(beg + mid), key))
  380. {
  381. down = mid + 1;
  382. }
  383. else
  384. {
  385. up = mid;
  386. }
  387. }
  388. return beg + down;
  389. }
  390. /*
  391. Performs binary search and returns iterator to an element that is equal to `key`,
  392. according to comparison `cmp`.
  393. Cmp should return true if first argument is less than second argument.
  394. Returned value is the found element, if present in the collection or end if not
  395. found.
  396. */
  397. template<typename CmpLess, typename IterT, typename KeyT>
  398. static IterT BinaryFindSorted(const IterT& beg, const IterT& end, const KeyT& value, const CmpLess& cmp)
  399. {
  400. IterT it = BinaryFindFirstNotLess<CmpLess, IterT, KeyT>(beg, end, value, cmp);
  401. if (it == end ||
  402. (!cmp(*it, value) && !cmp(value, *it)))
  403. {
  404. return it;
  405. }
  406. return end;
  407. }
  408. static UINT HeapTypeToIndex(D3D12_HEAP_TYPE type)
  409. {
  410. switch (type)
  411. {
  412. case D3D12_HEAP_TYPE_DEFAULT: return 0;
  413. case D3D12_HEAP_TYPE_UPLOAD: return 1;
  414. case D3D12_HEAP_TYPE_READBACK: return 2;
  415. case D3D12_HEAP_TYPE_CUSTOM: return 3;
  416. default: D3D12MA_ASSERT(0); return UINT_MAX;
  417. }
  418. }
  419. static D3D12_HEAP_TYPE IndexToHeapType(UINT heapTypeIndex)
  420. {
  421. D3D12MA_ASSERT(heapTypeIndex < 4);
  422. // D3D12_HEAP_TYPE_DEFAULT starts at 1.
  423. return (D3D12_HEAP_TYPE)(heapTypeIndex + 1);
  424. }
  425. static UINT64 HeapFlagsToAlignment(D3D12_HEAP_FLAGS flags, bool denyMsaaTextures)
  426. {
  427. /*
  428. Documentation of D3D12_HEAP_DESC structure says:
  429. - D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT defined as 64KB.
  430. - D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT defined as 4MB. An
  431. application must decide whether the heap will contain multi-sample
  432. anti-aliasing (MSAA), in which case, the application must choose [this flag].
  433. https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_heap_desc
  434. */
  435. if (denyMsaaTextures)
  436. return D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
  437. const D3D12_HEAP_FLAGS denyAllTexturesFlags =
  438. D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES | D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES;
  439. const bool canContainAnyTextures =
  440. (flags & denyAllTexturesFlags) != denyAllTexturesFlags;
  441. return canContainAnyTextures ?
  442. D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT : D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
  443. }
  444. static ResourceClass HeapFlagsToResourceClass(D3D12_HEAP_FLAGS heapFlags)
  445. {
  446. const bool allowBuffers = (heapFlags & D3D12_HEAP_FLAG_DENY_BUFFERS) == 0;
  447. const bool allowRtDsTextures = (heapFlags & D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES) == 0;
  448. const bool allowNonRtDsTextures = (heapFlags & D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES) == 0;
  449. const uint8_t allowedGroupCount = (allowBuffers ? 1 : 0) + (allowRtDsTextures ? 1 : 0) + (allowNonRtDsTextures ? 1 : 0);
  450. if (allowedGroupCount != 1)
  451. return ResourceClass::Unknown;
  452. if (allowRtDsTextures)
  453. return ResourceClass::RT_DS_Texture;
  454. if (allowNonRtDsTextures)
  455. return ResourceClass::Non_RT_DS_Texture;
  456. return ResourceClass::Buffer;
  457. }
  458. static bool IsHeapTypeStandard(D3D12_HEAP_TYPE type)
  459. {
  460. return type == D3D12_HEAP_TYPE_DEFAULT ||
  461. type == D3D12_HEAP_TYPE_UPLOAD ||
  462. type == D3D12_HEAP_TYPE_READBACK;
  463. }
  464. static D3D12_HEAP_PROPERTIES StandardHeapTypeToHeapProperties(D3D12_HEAP_TYPE type)
  465. {
  466. D3D12MA_ASSERT(IsHeapTypeStandard(type));
  467. D3D12_HEAP_PROPERTIES result = {};
  468. result.Type = type;
  469. return result;
  470. }
  471. static bool IsFormatCompressed(DXGI_FORMAT format)
  472. {
  473. switch (format)
  474. {
  475. case DXGI_FORMAT_BC1_TYPELESS:
  476. case DXGI_FORMAT_BC1_UNORM:
  477. case DXGI_FORMAT_BC1_UNORM_SRGB:
  478. case DXGI_FORMAT_BC2_TYPELESS:
  479. case DXGI_FORMAT_BC2_UNORM:
  480. case DXGI_FORMAT_BC2_UNORM_SRGB:
  481. case DXGI_FORMAT_BC3_TYPELESS:
  482. case DXGI_FORMAT_BC3_UNORM:
  483. case DXGI_FORMAT_BC3_UNORM_SRGB:
  484. case DXGI_FORMAT_BC4_TYPELESS:
  485. case DXGI_FORMAT_BC4_UNORM:
  486. case DXGI_FORMAT_BC4_SNORM:
  487. case DXGI_FORMAT_BC5_TYPELESS:
  488. case DXGI_FORMAT_BC5_UNORM:
  489. case DXGI_FORMAT_BC5_SNORM:
  490. case DXGI_FORMAT_BC6H_TYPELESS:
  491. case DXGI_FORMAT_BC6H_UF16:
  492. case DXGI_FORMAT_BC6H_SF16:
  493. case DXGI_FORMAT_BC7_TYPELESS:
  494. case DXGI_FORMAT_BC7_UNORM:
  495. case DXGI_FORMAT_BC7_UNORM_SRGB:
  496. return true;
  497. default:
  498. return false;
  499. }
  500. }
  501. // Only some formats are supported. For others it returns 0.
  502. static UINT GetBitsPerPixel(DXGI_FORMAT format)
  503. {
  504. switch (format)
  505. {
  506. case DXGI_FORMAT_R32G32B32A32_TYPELESS:
  507. case DXGI_FORMAT_R32G32B32A32_FLOAT:
  508. case DXGI_FORMAT_R32G32B32A32_UINT:
  509. case DXGI_FORMAT_R32G32B32A32_SINT:
  510. return 128;
  511. case DXGI_FORMAT_R32G32B32_TYPELESS:
  512. case DXGI_FORMAT_R32G32B32_FLOAT:
  513. case DXGI_FORMAT_R32G32B32_UINT:
  514. case DXGI_FORMAT_R32G32B32_SINT:
  515. return 96;
  516. case DXGI_FORMAT_R16G16B16A16_TYPELESS:
  517. case DXGI_FORMAT_R16G16B16A16_FLOAT:
  518. case DXGI_FORMAT_R16G16B16A16_UNORM:
  519. case DXGI_FORMAT_R16G16B16A16_UINT:
  520. case DXGI_FORMAT_R16G16B16A16_SNORM:
  521. case DXGI_FORMAT_R16G16B16A16_SINT:
  522. return 64;
  523. case DXGI_FORMAT_R32G32_TYPELESS:
  524. case DXGI_FORMAT_R32G32_FLOAT:
  525. case DXGI_FORMAT_R32G32_UINT:
  526. case DXGI_FORMAT_R32G32_SINT:
  527. return 64;
  528. case DXGI_FORMAT_R32G8X24_TYPELESS:
  529. case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
  530. case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
  531. case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
  532. return 64;
  533. case DXGI_FORMAT_R10G10B10A2_TYPELESS:
  534. case DXGI_FORMAT_R10G10B10A2_UNORM:
  535. case DXGI_FORMAT_R10G10B10A2_UINT:
  536. case DXGI_FORMAT_R11G11B10_FLOAT:
  537. return 32;
  538. case DXGI_FORMAT_R8G8B8A8_TYPELESS:
  539. case DXGI_FORMAT_R8G8B8A8_UNORM:
  540. case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
  541. case DXGI_FORMAT_R8G8B8A8_UINT:
  542. case DXGI_FORMAT_R8G8B8A8_SNORM:
  543. case DXGI_FORMAT_R8G8B8A8_SINT:
  544. return 32;
  545. case DXGI_FORMAT_R16G16_TYPELESS:
  546. case DXGI_FORMAT_R16G16_FLOAT:
  547. case DXGI_FORMAT_R16G16_UNORM:
  548. case DXGI_FORMAT_R16G16_UINT:
  549. case DXGI_FORMAT_R16G16_SNORM:
  550. case DXGI_FORMAT_R16G16_SINT:
  551. return 32;
  552. case DXGI_FORMAT_R32_TYPELESS:
  553. case DXGI_FORMAT_D32_FLOAT:
  554. case DXGI_FORMAT_R32_FLOAT:
  555. case DXGI_FORMAT_R32_UINT:
  556. case DXGI_FORMAT_R32_SINT:
  557. return 32;
  558. case DXGI_FORMAT_R24G8_TYPELESS:
  559. case DXGI_FORMAT_D24_UNORM_S8_UINT:
  560. case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
  561. case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
  562. return 32;
  563. case DXGI_FORMAT_R8G8_TYPELESS:
  564. case DXGI_FORMAT_R8G8_UNORM:
  565. case DXGI_FORMAT_R8G8_UINT:
  566. case DXGI_FORMAT_R8G8_SNORM:
  567. case DXGI_FORMAT_R8G8_SINT:
  568. return 16;
  569. case DXGI_FORMAT_R16_TYPELESS:
  570. case DXGI_FORMAT_R16_FLOAT:
  571. case DXGI_FORMAT_D16_UNORM:
  572. case DXGI_FORMAT_R16_UNORM:
  573. case DXGI_FORMAT_R16_UINT:
  574. case DXGI_FORMAT_R16_SNORM:
  575. case DXGI_FORMAT_R16_SINT:
  576. return 16;
  577. case DXGI_FORMAT_R8_TYPELESS:
  578. case DXGI_FORMAT_R8_UNORM:
  579. case DXGI_FORMAT_R8_UINT:
  580. case DXGI_FORMAT_R8_SNORM:
  581. case DXGI_FORMAT_R8_SINT:
  582. case DXGI_FORMAT_A8_UNORM:
  583. return 8;
  584. case DXGI_FORMAT_BC1_TYPELESS:
  585. case DXGI_FORMAT_BC1_UNORM:
  586. case DXGI_FORMAT_BC1_UNORM_SRGB:
  587. return 4;
  588. case DXGI_FORMAT_BC2_TYPELESS:
  589. case DXGI_FORMAT_BC2_UNORM:
  590. case DXGI_FORMAT_BC2_UNORM_SRGB:
  591. return 8;
  592. case DXGI_FORMAT_BC3_TYPELESS:
  593. case DXGI_FORMAT_BC3_UNORM:
  594. case DXGI_FORMAT_BC3_UNORM_SRGB:
  595. return 8;
  596. case DXGI_FORMAT_BC4_TYPELESS:
  597. case DXGI_FORMAT_BC4_UNORM:
  598. case DXGI_FORMAT_BC4_SNORM:
  599. return 4;
  600. case DXGI_FORMAT_BC5_TYPELESS:
  601. case DXGI_FORMAT_BC5_UNORM:
  602. case DXGI_FORMAT_BC5_SNORM:
  603. return 8;
  604. case DXGI_FORMAT_BC6H_TYPELESS:
  605. case DXGI_FORMAT_BC6H_UF16:
  606. case DXGI_FORMAT_BC6H_SF16:
  607. return 8;
  608. case DXGI_FORMAT_BC7_TYPELESS:
  609. case DXGI_FORMAT_BC7_UNORM:
  610. case DXGI_FORMAT_BC7_UNORM_SRGB:
  611. return 8;
  612. default:
  613. return 0;
  614. }
  615. }
  616. template<typename D3D12_RESOURCE_DESC_T>
  617. static ResourceClass ResourceDescToResourceClass(const D3D12_RESOURCE_DESC_T& resDesc)
  618. {
  619. if (resDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
  620. return ResourceClass::Buffer;
  621. // Else: it's surely a texture.
  622. const bool isRenderTargetOrDepthStencil =
  623. (resDesc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) != 0;
  624. return isRenderTargetOrDepthStencil ? ResourceClass::RT_DS_Texture : ResourceClass::Non_RT_DS_Texture;
  625. }
  626. // This algorithm is overly conservative.
  627. template<typename D3D12_RESOURCE_DESC_T>
  628. static bool CanUseSmallAlignment(const D3D12_RESOURCE_DESC_T& resourceDesc)
  629. {
  630. if (resourceDesc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D)
  631. return false;
  632. if ((resourceDesc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) != 0)
  633. return false;
  634. if (resourceDesc.SampleDesc.Count > 1)
  635. return false;
  636. if (resourceDesc.DepthOrArraySize != 1)
  637. return false;
  638. UINT sizeX = (UINT)resourceDesc.Width;
  639. UINT sizeY = resourceDesc.Height;
  640. UINT bitsPerPixel = GetBitsPerPixel(resourceDesc.Format);
  641. if (bitsPerPixel == 0)
  642. return false;
  643. if (IsFormatCompressed(resourceDesc.Format))
  644. {
  645. sizeX = DivideRoundingUp(sizeX, 4u);
  646. sizeY = DivideRoundingUp(sizeY, 4u);
  647. bitsPerPixel *= 16;
  648. }
  649. UINT tileSizeX = 0, tileSizeY = 0;
  650. switch (bitsPerPixel)
  651. {
  652. case 8: tileSizeX = 64; tileSizeY = 64; break;
  653. case 16: tileSizeX = 64; tileSizeY = 32; break;
  654. case 32: tileSizeX = 32; tileSizeY = 32; break;
  655. case 64: tileSizeX = 32; tileSizeY = 16; break;
  656. case 128: tileSizeX = 16; tileSizeY = 16; break;
  657. default: return false;
  658. }
  659. const UINT tileCount = DivideRoundingUp(sizeX, tileSizeX) * DivideRoundingUp(sizeY, tileSizeY);
  660. return tileCount <= 16;
  661. }
  662. static bool ValidateAllocateMemoryParameters(
  663. const ALLOCATION_DESC* pAllocDesc,
  664. const D3D12_RESOURCE_ALLOCATION_INFO* pAllocInfo,
  665. Allocation** ppAllocation)
  666. {
  667. return pAllocDesc &&
  668. pAllocInfo &&
  669. ppAllocation &&
  670. (pAllocInfo->Alignment == 0 ||
  671. pAllocInfo->Alignment == D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT ||
  672. pAllocInfo->Alignment == D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT) &&
  673. pAllocInfo->SizeInBytes != 0 &&
  674. pAllocInfo->SizeInBytes % (64ull * 1024) == 0;
  675. }
  676. #endif // _D3D12MA_FUNCTIONS
  677. #ifndef _D3D12MA_STATISTICS_FUNCTIONS
  678. static void ClearStatistics(Statistics& outStats)
  679. {
  680. outStats.BlockCount = 0;
  681. outStats.AllocationCount = 0;
  682. outStats.BlockBytes = 0;
  683. outStats.AllocationBytes = 0;
  684. }
  685. static void ClearDetailedStatistics(DetailedStatistics& outStats)
  686. {
  687. ClearStatistics(outStats.Stats);
  688. outStats.UnusedRangeCount = 0;
  689. outStats.AllocationSizeMin = UINT64_MAX;
  690. outStats.AllocationSizeMax = 0;
  691. outStats.UnusedRangeSizeMin = UINT64_MAX;
  692. outStats.UnusedRangeSizeMax = 0;
  693. }
  694. static void AddStatistics(Statistics& inoutStats, const Statistics& src)
  695. {
  696. inoutStats.BlockCount += src.BlockCount;
  697. inoutStats.AllocationCount += src.AllocationCount;
  698. inoutStats.BlockBytes += src.BlockBytes;
  699. inoutStats.AllocationBytes += src.AllocationBytes;
  700. }
  701. static void AddDetailedStatistics(DetailedStatistics& inoutStats, const DetailedStatistics& src)
  702. {
  703. AddStatistics(inoutStats.Stats, src.Stats);
  704. inoutStats.UnusedRangeCount += src.UnusedRangeCount;
  705. inoutStats.AllocationSizeMin = D3D12MA_MIN(inoutStats.AllocationSizeMin, src.AllocationSizeMin);
  706. inoutStats.AllocationSizeMax = D3D12MA_MAX(inoutStats.AllocationSizeMax, src.AllocationSizeMax);
  707. inoutStats.UnusedRangeSizeMin = D3D12MA_MIN(inoutStats.UnusedRangeSizeMin, src.UnusedRangeSizeMin);
  708. inoutStats.UnusedRangeSizeMax = D3D12MA_MAX(inoutStats.UnusedRangeSizeMax, src.UnusedRangeSizeMax);
  709. }
  710. static void AddDetailedStatisticsAllocation(DetailedStatistics& inoutStats, UINT64 size)
  711. {
  712. inoutStats.Stats.AllocationCount++;
  713. inoutStats.Stats.AllocationBytes += size;
  714. inoutStats.AllocationSizeMin = D3D12MA_MIN(inoutStats.AllocationSizeMin, size);
  715. inoutStats.AllocationSizeMax = D3D12MA_MAX(inoutStats.AllocationSizeMax, size);
  716. }
  717. static void AddDetailedStatisticsUnusedRange(DetailedStatistics& inoutStats, UINT64 size)
  718. {
  719. inoutStats.UnusedRangeCount++;
  720. inoutStats.UnusedRangeSizeMin = D3D12MA_MIN(inoutStats.UnusedRangeSizeMin, size);
  721. inoutStats.UnusedRangeSizeMax = D3D12MA_MAX(inoutStats.UnusedRangeSizeMax, size);
  722. }
  723. #endif // _D3D12MA_STATISTICS_FUNCTIONS
  724. #ifndef _D3D12MA_MUTEX
  725. #ifndef D3D12MA_MUTEX
  726. class Mutex
  727. {
  728. public:
  729. void Lock() { m_Mutex.lock(); }
  730. void Unlock() { m_Mutex.unlock(); }
  731. private:
  732. std::mutex m_Mutex;
  733. };
  734. #define D3D12MA_MUTEX Mutex
  735. #endif
  736. #ifndef D3D12MA_RW_MUTEX
  737. #ifdef _WIN32
  738. class RWMutex
  739. {
  740. public:
  741. RWMutex() { InitializeSRWLock(&m_Lock); }
  742. void LockRead() { AcquireSRWLockShared(&m_Lock); }
  743. void UnlockRead() { ReleaseSRWLockShared(&m_Lock); }
  744. void LockWrite() { AcquireSRWLockExclusive(&m_Lock); }
  745. void UnlockWrite() { ReleaseSRWLockExclusive(&m_Lock); }
  746. private:
  747. SRWLOCK m_Lock;
  748. };
  749. #else // #ifdef _WIN32
  750. class RWMutex
  751. {
  752. public:
  753. RWMutex() {}
  754. void LockRead() { m_Mutex.lock_shared(); }
  755. void UnlockRead() { m_Mutex.unlock_shared(); }
  756. void LockWrite() { m_Mutex.lock(); }
  757. void UnlockWrite() { m_Mutex.unlock(); }
  758. private:
  759. std::shared_timed_mutex m_Mutex;
  760. };
  761. #endif // #ifdef _WIN32
  762. #define D3D12MA_RW_MUTEX RWMutex
  763. #endif // #ifndef D3D12MA_RW_MUTEX
  764. // Helper RAII class to lock a mutex in constructor and unlock it in destructor (at the end of scope).
  765. struct MutexLock
  766. {
  767. D3D12MA_CLASS_NO_COPY(MutexLock);
  768. public:
  769. MutexLock(D3D12MA_MUTEX& mutex, bool useMutex = true) :
  770. m_pMutex(useMutex ? &mutex : NULL)
  771. {
  772. if (m_pMutex) m_pMutex->Lock();
  773. }
  774. ~MutexLock() { if (m_pMutex) m_pMutex->Unlock(); }
  775. private:
  776. D3D12MA_MUTEX* m_pMutex;
  777. };
  778. // Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for reading.
  779. struct MutexLockRead
  780. {
  781. D3D12MA_CLASS_NO_COPY(MutexLockRead);
  782. public:
  783. MutexLockRead(D3D12MA_RW_MUTEX& mutex, bool useMutex)
  784. : m_pMutex(useMutex ? &mutex : NULL)
  785. {
  786. if(m_pMutex)
  787. {
  788. m_pMutex->LockRead();
  789. }
  790. }
  791. ~MutexLockRead() { if (m_pMutex) m_pMutex->UnlockRead(); }
  792. private:
  793. D3D12MA_RW_MUTEX* m_pMutex;
  794. };
  795. // Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for writing.
  796. struct MutexLockWrite
  797. {
  798. D3D12MA_CLASS_NO_COPY(MutexLockWrite);
  799. public:
  800. MutexLockWrite(D3D12MA_RW_MUTEX& mutex, bool useMutex)
  801. : m_pMutex(useMutex ? &mutex : NULL)
  802. {
  803. if (m_pMutex) m_pMutex->LockWrite();
  804. }
  805. ~MutexLockWrite() { if (m_pMutex) m_pMutex->UnlockWrite(); }
  806. private:
  807. D3D12MA_RW_MUTEX* m_pMutex;
  808. };
  809. #if D3D12MA_DEBUG_GLOBAL_MUTEX
  810. static D3D12MA_MUTEX g_DebugGlobalMutex;
  811. #define D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK MutexLock debugGlobalMutexLock(g_DebugGlobalMutex, true);
  812. #else
  813. #define D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  814. #endif
  815. #endif // _D3D12MA_MUTEX
  816. #ifndef _D3D12MA_VECTOR
  817. /*
  818. Dynamically resizing continuous array. Class with interface similar to std::vector.
  819. T must be POD because constructors and destructors are not called and memcpy is
  820. used for these objects.
  821. */
  822. template<typename T>
  823. class Vector
  824. {
  825. public:
  826. using value_type = T;
  827. using iterator = T*;
  828. using const_iterator = const T*;
  829. // allocationCallbacks externally owned, must outlive this object.
  830. Vector(const ALLOCATION_CALLBACKS& allocationCallbacks);
  831. Vector(size_t count, const ALLOCATION_CALLBACKS& allocationCallbacks);
  832. Vector(const Vector<T>& src);
  833. ~Vector();
  834. const ALLOCATION_CALLBACKS& GetAllocs() const { return m_AllocationCallbacks; }
  835. bool empty() const { return m_Count == 0; }
  836. size_t size() const { return m_Count; }
  837. T* data() { return m_pArray; }
  838. const T* data() const { return m_pArray; }
  839. void clear(bool freeMemory = false) { resize(0, freeMemory); }
  840. iterator begin() { return m_pArray; }
  841. iterator end() { return m_pArray + m_Count; }
  842. const_iterator cbegin() const { return m_pArray; }
  843. const_iterator cend() const { return m_pArray + m_Count; }
  844. const_iterator begin() const { return cbegin(); }
  845. const_iterator end() const { return cend(); }
  846. void push_front(const T& src) { insert(0, src); }
  847. void push_back(const T& src);
  848. void pop_front();
  849. void pop_back();
  850. T& front();
  851. T& back();
  852. const T& front() const;
  853. const T& back() const;
  854. void reserve(size_t newCapacity, bool freeMemory = false);
  855. void resize(size_t newCount, bool freeMemory = false);
  856. void insert(size_t index, const T& src);
  857. void remove(size_t index);
  858. template<typename CmpLess>
  859. size_t InsertSorted(const T& value, const CmpLess& cmp);
  860. template<typename CmpLess>
  861. bool RemoveSorted(const T& value, const CmpLess& cmp);
  862. Vector& operator=(const Vector<T>& rhs);
  863. T& operator[](size_t index);
  864. const T& operator[](size_t index) const;
  865. private:
  866. const ALLOCATION_CALLBACKS& m_AllocationCallbacks;
  867. T* m_pArray;
  868. size_t m_Count;
  869. size_t m_Capacity;
  870. };
  871. #ifndef _D3D12MA_VECTOR_FUNCTIONS
  872. template<typename T>
  873. Vector<T>::Vector(const ALLOCATION_CALLBACKS& allocationCallbacks)
  874. : m_AllocationCallbacks(allocationCallbacks),
  875. m_pArray(NULL),
  876. m_Count(0),
  877. m_Capacity(0) {}
  878. template<typename T>
  879. Vector<T>::Vector(size_t count, const ALLOCATION_CALLBACKS& allocationCallbacks)
  880. : m_AllocationCallbacks(allocationCallbacks),
  881. m_pArray(count ? AllocateArray<T>(allocationCallbacks, count) : NULL),
  882. m_Count(count),
  883. m_Capacity(count) {}
  884. template<typename T>
  885. Vector<T>::Vector(const Vector<T>& src)
  886. : m_AllocationCallbacks(src.m_AllocationCallbacks),
  887. m_pArray(src.m_Count ? AllocateArray<T>(src.m_AllocationCallbacks, src.m_Count) : NULL),
  888. m_Count(src.m_Count),
  889. m_Capacity(src.m_Count)
  890. {
  891. if (m_Count > 0)
  892. {
  893. memcpy(m_pArray, src.m_pArray, m_Count * sizeof(T));
  894. }
  895. }
  896. template<typename T>
  897. Vector<T>::~Vector()
  898. {
  899. Free(m_AllocationCallbacks, m_pArray);
  900. }
  901. template<typename T>
  902. void Vector<T>::push_back(const T& src)
  903. {
  904. const size_t newIndex = size();
  905. resize(newIndex + 1);
  906. m_pArray[newIndex] = src;
  907. }
  908. template<typename T>
  909. void Vector<T>::pop_front()
  910. {
  911. D3D12MA_HEAVY_ASSERT(m_Count > 0);
  912. remove(0);
  913. }
  914. template<typename T>
  915. void Vector<T>::pop_back()
  916. {
  917. D3D12MA_HEAVY_ASSERT(m_Count > 0);
  918. resize(size() - 1);
  919. }
  920. template<typename T>
  921. T& Vector<T>::front()
  922. {
  923. D3D12MA_HEAVY_ASSERT(m_Count > 0);
  924. return m_pArray[0];
  925. }
  926. template<typename T>
  927. T& Vector<T>::back()
  928. {
  929. D3D12MA_HEAVY_ASSERT(m_Count > 0);
  930. return m_pArray[m_Count - 1];
  931. }
  932. template<typename T>
  933. const T& Vector<T>::front() const
  934. {
  935. D3D12MA_HEAVY_ASSERT(m_Count > 0);
  936. return m_pArray[0];
  937. }
  938. template<typename T>
  939. const T& Vector<T>::back() const
  940. {
  941. D3D12MA_HEAVY_ASSERT(m_Count > 0);
  942. return m_pArray[m_Count - 1];
  943. }
  944. template<typename T>
  945. void Vector<T>::reserve(size_t newCapacity, bool freeMemory)
  946. {
  947. newCapacity = D3D12MA_MAX(newCapacity, m_Count);
  948. if ((newCapacity < m_Capacity) && !freeMemory)
  949. {
  950. newCapacity = m_Capacity;
  951. }
  952. if (newCapacity != m_Capacity)
  953. {
  954. T* const newArray = newCapacity ? AllocateArray<T>(m_AllocationCallbacks, newCapacity) : NULL;
  955. if (m_Count != 0)
  956. {
  957. memcpy(newArray, m_pArray, m_Count * sizeof(T));
  958. }
  959. Free(m_AllocationCallbacks, m_pArray);
  960. m_Capacity = newCapacity;
  961. m_pArray = newArray;
  962. }
  963. }
  964. template<typename T>
  965. void Vector<T>::resize(size_t newCount, bool freeMemory)
  966. {
  967. size_t newCapacity = m_Capacity;
  968. if (newCount > m_Capacity)
  969. {
  970. newCapacity = D3D12MA_MAX(newCount, D3D12MA_MAX(m_Capacity * 3 / 2, (size_t)8));
  971. }
  972. else if (freeMemory)
  973. {
  974. newCapacity = newCount;
  975. }
  976. if (newCapacity != m_Capacity)
  977. {
  978. T* const newArray = newCapacity ? AllocateArray<T>(m_AllocationCallbacks, newCapacity) : NULL;
  979. const size_t elementsToCopy = D3D12MA_MIN(m_Count, newCount);
  980. if (elementsToCopy != 0)
  981. {
  982. memcpy(newArray, m_pArray, elementsToCopy * sizeof(T));
  983. }
  984. Free(m_AllocationCallbacks, m_pArray);
  985. m_Capacity = newCapacity;
  986. m_pArray = newArray;
  987. }
  988. m_Count = newCount;
  989. }
  990. template<typename T>
  991. void Vector<T>::insert(size_t index, const T& src)
  992. {
  993. D3D12MA_HEAVY_ASSERT(index <= m_Count);
  994. const size_t oldCount = size();
  995. resize(oldCount + 1);
  996. if (index < oldCount)
  997. {
  998. memmove(m_pArray + (index + 1), m_pArray + index, (oldCount - index) * sizeof(T));
  999. }
  1000. m_pArray[index] = src;
  1001. }
  1002. template<typename T>
  1003. void Vector<T>::remove(size_t index)
  1004. {
  1005. D3D12MA_HEAVY_ASSERT(index < m_Count);
  1006. const size_t oldCount = size();
  1007. if (index < oldCount - 1)
  1008. {
  1009. memmove(m_pArray + index, m_pArray + (index + 1), (oldCount - index - 1) * sizeof(T));
  1010. }
  1011. resize(oldCount - 1);
  1012. }
  1013. template<typename T> template<typename CmpLess>
  1014. size_t Vector<T>::InsertSorted(const T& value, const CmpLess& cmp)
  1015. {
  1016. const size_t indexToInsert = BinaryFindFirstNotLess<CmpLess, iterator, T>(
  1017. m_pArray,
  1018. m_pArray + m_Count,
  1019. value,
  1020. cmp) - m_pArray;
  1021. insert(indexToInsert, value);
  1022. return indexToInsert;
  1023. }
  1024. template<typename T> template<typename CmpLess>
  1025. bool Vector<T>::RemoveSorted(const T& value, const CmpLess& cmp)
  1026. {
  1027. const iterator it = BinaryFindFirstNotLess(
  1028. m_pArray,
  1029. m_pArray + m_Count,
  1030. value,
  1031. cmp);
  1032. if ((it != end()) && !cmp(*it, value) && !cmp(value, *it))
  1033. {
  1034. size_t indexToRemove = it - begin();
  1035. remove(indexToRemove);
  1036. return true;
  1037. }
  1038. return false;
  1039. }
  1040. template<typename T>
  1041. Vector<T>& Vector<T>::operator=(const Vector<T>& rhs)
  1042. {
  1043. if (&rhs != this)
  1044. {
  1045. resize(rhs.m_Count);
  1046. if (m_Count != 0)
  1047. {
  1048. memcpy(m_pArray, rhs.m_pArray, m_Count * sizeof(T));
  1049. }
  1050. }
  1051. return *this;
  1052. }
  1053. template<typename T>
  1054. T& Vector<T>::operator[](size_t index)
  1055. {
  1056. D3D12MA_HEAVY_ASSERT(index < m_Count);
  1057. return m_pArray[index];
  1058. }
  1059. template<typename T>
  1060. const T& Vector<T>::operator[](size_t index) const
  1061. {
  1062. D3D12MA_HEAVY_ASSERT(index < m_Count);
  1063. return m_pArray[index];
  1064. }
  1065. #endif // _D3D12MA_VECTOR_FUNCTIONS
  1066. #endif // _D3D12MA_VECTOR
  1067. #ifndef _D3D12MA_STRING_BUILDER
  1068. class StringBuilder
  1069. {
  1070. public:
  1071. StringBuilder(const ALLOCATION_CALLBACKS& allocationCallbacks) : m_Data(allocationCallbacks) {}
  1072. size_t GetLength() const { return m_Data.size(); }
  1073. LPCWSTR GetData() const { return m_Data.data(); }
  1074. void Add(WCHAR ch) { m_Data.push_back(ch); }
  1075. void Add(LPCWSTR str);
  1076. void AddNewLine() { Add(L'\n'); }
  1077. void AddNumber(UINT num);
  1078. void AddNumber(UINT64 num);
  1079. void AddPointer(const void* ptr);
  1080. private:
  1081. Vector<WCHAR> m_Data;
  1082. };
  1083. #ifndef _D3D12MA_STRING_BUILDER_FUNCTIONS
  1084. void StringBuilder::Add(LPCWSTR str)
  1085. {
  1086. const size_t len = wcslen(str);
  1087. if (len > 0)
  1088. {
  1089. const size_t oldCount = m_Data.size();
  1090. m_Data.resize(oldCount + len);
  1091. memcpy(m_Data.data() + oldCount, str, len * sizeof(WCHAR));
  1092. }
  1093. }
  1094. void StringBuilder::AddNumber(UINT num)
  1095. {
  1096. WCHAR buf[11];
  1097. buf[10] = L'\0';
  1098. WCHAR *p = &buf[10];
  1099. do
  1100. {
  1101. *--p = L'0' + (num % 10);
  1102. num /= 10;
  1103. }
  1104. while (num);
  1105. Add(p);
  1106. }
  1107. void StringBuilder::AddNumber(UINT64 num)
  1108. {
  1109. WCHAR buf[21];
  1110. buf[20] = L'\0';
  1111. WCHAR *p = &buf[20];
  1112. do
  1113. {
  1114. *--p = L'0' + (num % 10);
  1115. num /= 10;
  1116. }
  1117. while (num);
  1118. Add(p);
  1119. }
  1120. void StringBuilder::AddPointer(const void* ptr)
  1121. {
  1122. WCHAR buf[21];
  1123. uintptr_t num = (uintptr_t)ptr;
  1124. buf[20] = L'\0';
  1125. WCHAR *p = &buf[20];
  1126. do
  1127. {
  1128. *--p = HexDigitToChar((UINT8)(num & 0xF));
  1129. num >>= 4;
  1130. }
  1131. while (num);
  1132. Add(p);
  1133. }
  1134. #endif // _D3D12MA_STRING_BUILDER_FUNCTIONS
  1135. #endif // _D3D12MA_STRING_BUILDER
  1136. #ifndef _D3D12MA_JSON_WRITER
  1137. /*
  1138. Allows to conveniently build a correct JSON document to be written to the
  1139. StringBuilder passed to the constructor.
  1140. */
  1141. class JsonWriter
  1142. {
  1143. public:
  1144. // stringBuilder - string builder to write the document to. Must remain alive for the whole lifetime of this object.
  1145. JsonWriter(const ALLOCATION_CALLBACKS& allocationCallbacks, StringBuilder& stringBuilder);
  1146. ~JsonWriter();
  1147. // Begins object by writing "{".
  1148. // Inside an object, you must call pairs of WriteString and a value, e.g.:
  1149. // j.BeginObject(true); j.WriteString("A"); j.WriteNumber(1); j.WriteString("B"); j.WriteNumber(2); j.EndObject();
  1150. // Will write: { "A": 1, "B": 2 }
  1151. void BeginObject(bool singleLine = false);
  1152. // Ends object by writing "}".
  1153. void EndObject();
  1154. // Begins array by writing "[".
  1155. // Inside an array, you can write a sequence of any values.
  1156. void BeginArray(bool singleLine = false);
  1157. // Ends array by writing "[".
  1158. void EndArray();
  1159. // Writes a string value inside "".
  1160. // pStr can contain any UTF-16 characters, including '"', new line etc. - they will be properly escaped.
  1161. void WriteString(LPCWSTR pStr);
  1162. // Begins writing a string value.
  1163. // Call BeginString, ContinueString, ContinueString, ..., EndString instead of
  1164. // WriteString to conveniently build the string content incrementally, made of
  1165. // parts including numbers.
  1166. void BeginString(LPCWSTR pStr = NULL);
  1167. // Posts next part of an open string.
  1168. void ContinueString(LPCWSTR pStr);
  1169. // Posts next part of an open string. The number is converted to decimal characters.
  1170. void ContinueString(UINT num);
  1171. void ContinueString(UINT64 num);
  1172. void ContinueString_Pointer(const void* ptr);
  1173. // Posts next part of an open string. Pointer value is converted to characters
  1174. // using "%p" formatting - shown as hexadecimal number, e.g.: 000000081276Ad00
  1175. // void ContinueString_Pointer(const void* ptr);
  1176. // Ends writing a string value by writing '"'.
  1177. void EndString(LPCWSTR pStr = NULL);
  1178. // Writes a number value.
  1179. void WriteNumber(UINT num);
  1180. void WriteNumber(UINT64 num);
  1181. // Writes a boolean value - false or true.
  1182. void WriteBool(bool b);
  1183. // Writes a null value.
  1184. void WriteNull();
  1185. void AddAllocationToObject(const Allocation& alloc);
  1186. void AddDetailedStatisticsInfoObject(const DetailedStatistics& stats);
  1187. private:
  1188. static const WCHAR* const INDENT;
  1189. enum CollectionType
  1190. {
  1191. COLLECTION_TYPE_OBJECT,
  1192. COLLECTION_TYPE_ARRAY,
  1193. };
  1194. struct StackItem
  1195. {
  1196. CollectionType type;
  1197. UINT valueCount;
  1198. bool singleLineMode;
  1199. };
  1200. StringBuilder& m_SB;
  1201. Vector<StackItem> m_Stack;
  1202. bool m_InsideString;
  1203. void BeginValue(bool isString);
  1204. void WriteIndent(bool oneLess = false);
  1205. };
  1206. #ifndef _D3D12MA_JSON_WRITER_FUNCTIONS
  1207. const WCHAR* const JsonWriter::INDENT = L" ";
  1208. JsonWriter::JsonWriter(const ALLOCATION_CALLBACKS& allocationCallbacks, StringBuilder& stringBuilder)
  1209. : m_SB(stringBuilder),
  1210. m_Stack(allocationCallbacks),
  1211. m_InsideString(false) {}
  1212. JsonWriter::~JsonWriter()
  1213. {
  1214. D3D12MA_ASSERT(!m_InsideString);
  1215. D3D12MA_ASSERT(m_Stack.empty());
  1216. }
  1217. void JsonWriter::BeginObject(bool singleLine)
  1218. {
  1219. D3D12MA_ASSERT(!m_InsideString);
  1220. BeginValue(false);
  1221. m_SB.Add(L'{');
  1222. StackItem stackItem;
  1223. stackItem.type = COLLECTION_TYPE_OBJECT;
  1224. stackItem.valueCount = 0;
  1225. stackItem.singleLineMode = singleLine;
  1226. m_Stack.push_back(stackItem);
  1227. }
  1228. void JsonWriter::EndObject()
  1229. {
  1230. D3D12MA_ASSERT(!m_InsideString);
  1231. D3D12MA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_OBJECT);
  1232. D3D12MA_ASSERT(m_Stack.back().valueCount % 2 == 0);
  1233. WriteIndent(true);
  1234. m_SB.Add(L'}');
  1235. m_Stack.pop_back();
  1236. }
  1237. void JsonWriter::BeginArray(bool singleLine)
  1238. {
  1239. D3D12MA_ASSERT(!m_InsideString);
  1240. BeginValue(false);
  1241. m_SB.Add(L'[');
  1242. StackItem stackItem;
  1243. stackItem.type = COLLECTION_TYPE_ARRAY;
  1244. stackItem.valueCount = 0;
  1245. stackItem.singleLineMode = singleLine;
  1246. m_Stack.push_back(stackItem);
  1247. }
  1248. void JsonWriter::EndArray()
  1249. {
  1250. D3D12MA_ASSERT(!m_InsideString);
  1251. D3D12MA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_ARRAY);
  1252. WriteIndent(true);
  1253. m_SB.Add(L']');
  1254. m_Stack.pop_back();
  1255. }
  1256. void JsonWriter::WriteString(LPCWSTR pStr)
  1257. {
  1258. BeginString(pStr);
  1259. EndString();
  1260. }
  1261. void JsonWriter::BeginString(LPCWSTR pStr)
  1262. {
  1263. D3D12MA_ASSERT(!m_InsideString);
  1264. BeginValue(true);
  1265. m_InsideString = true;
  1266. m_SB.Add(L'"');
  1267. if (pStr != NULL)
  1268. {
  1269. ContinueString(pStr);
  1270. }
  1271. }
  1272. void JsonWriter::ContinueString(LPCWSTR pStr)
  1273. {
  1274. D3D12MA_ASSERT(m_InsideString);
  1275. D3D12MA_ASSERT(pStr);
  1276. for (const WCHAR *p = pStr; *p; ++p)
  1277. {
  1278. // the strings we encode are assumed to be in UTF-16LE format, the native
  1279. // windows wide character Unicode format. In this encoding Unicode code
  1280. // points U+0000 to U+D7FF and U+E000 to U+FFFF are encoded in two bytes,
  1281. // and everything else takes more than two bytes. We will reject any
  1282. // multi wchar character encodings for simplicity.
  1283. UINT val = (UINT)*p;
  1284. D3D12MA_ASSERT(((val <= 0xD7FF) || (0xE000 <= val && val <= 0xFFFF)) &&
  1285. "Character not currently supported.");
  1286. switch (*p)
  1287. {
  1288. case L'"': m_SB.Add(L'\\'); m_SB.Add(L'"'); break;
  1289. case L'\\': m_SB.Add(L'\\'); m_SB.Add(L'\\'); break;
  1290. case L'/': m_SB.Add(L'\\'); m_SB.Add(L'/'); break;
  1291. case L'\b': m_SB.Add(L'\\'); m_SB.Add(L'b'); break;
  1292. case L'\f': m_SB.Add(L'\\'); m_SB.Add(L'f'); break;
  1293. case L'\n': m_SB.Add(L'\\'); m_SB.Add(L'n'); break;
  1294. case L'\r': m_SB.Add(L'\\'); m_SB.Add(L'r'); break;
  1295. case L'\t': m_SB.Add(L'\\'); m_SB.Add(L't'); break;
  1296. default:
  1297. // conservatively use encoding \uXXXX for any Unicode character
  1298. // requiring more than one byte.
  1299. if (32 <= val && val < 256)
  1300. m_SB.Add(*p);
  1301. else
  1302. {
  1303. m_SB.Add(L'\\');
  1304. m_SB.Add(L'u');
  1305. for (UINT i = 0; i < 4; ++i)
  1306. {
  1307. UINT hexDigit = (val & 0xF000) >> 12;
  1308. val <<= 4;
  1309. if (hexDigit < 10)
  1310. m_SB.Add(L'0' + (WCHAR)hexDigit);
  1311. else
  1312. m_SB.Add(L'A' + (WCHAR)hexDigit);
  1313. }
  1314. }
  1315. break;
  1316. }
  1317. }
  1318. }
  1319. void JsonWriter::ContinueString(UINT num)
  1320. {
  1321. D3D12MA_ASSERT(m_InsideString);
  1322. m_SB.AddNumber(num);
  1323. }
  1324. void JsonWriter::ContinueString(UINT64 num)
  1325. {
  1326. D3D12MA_ASSERT(m_InsideString);
  1327. m_SB.AddNumber(num);
  1328. }
  1329. void JsonWriter::ContinueString_Pointer(const void* ptr)
  1330. {
  1331. D3D12MA_ASSERT(m_InsideString);
  1332. m_SB.AddPointer(ptr);
  1333. }
  1334. void JsonWriter::EndString(LPCWSTR pStr)
  1335. {
  1336. D3D12MA_ASSERT(m_InsideString);
  1337. if (pStr)
  1338. ContinueString(pStr);
  1339. m_SB.Add(L'"');
  1340. m_InsideString = false;
  1341. }
  1342. void JsonWriter::WriteNumber(UINT num)
  1343. {
  1344. D3D12MA_ASSERT(!m_InsideString);
  1345. BeginValue(false);
  1346. m_SB.AddNumber(num);
  1347. }
  1348. void JsonWriter::WriteNumber(UINT64 num)
  1349. {
  1350. D3D12MA_ASSERT(!m_InsideString);
  1351. BeginValue(false);
  1352. m_SB.AddNumber(num);
  1353. }
  1354. void JsonWriter::WriteBool(bool b)
  1355. {
  1356. D3D12MA_ASSERT(!m_InsideString);
  1357. BeginValue(false);
  1358. if (b)
  1359. m_SB.Add(L"true");
  1360. else
  1361. m_SB.Add(L"false");
  1362. }
  1363. void JsonWriter::WriteNull()
  1364. {
  1365. D3D12MA_ASSERT(!m_InsideString);
  1366. BeginValue(false);
  1367. m_SB.Add(L"null");
  1368. }
  1369. void JsonWriter::AddAllocationToObject(const Allocation& alloc)
  1370. {
  1371. WriteString(L"Type");
  1372. switch (alloc.m_PackedData.GetResourceDimension()) {
  1373. case D3D12_RESOURCE_DIMENSION_UNKNOWN:
  1374. WriteString(L"UNKNOWN");
  1375. break;
  1376. case D3D12_RESOURCE_DIMENSION_BUFFER:
  1377. WriteString(L"BUFFER");
  1378. break;
  1379. case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
  1380. WriteString(L"TEXTURE1D");
  1381. break;
  1382. case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
  1383. WriteString(L"TEXTURE2D");
  1384. break;
  1385. case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
  1386. WriteString(L"TEXTURE3D");
  1387. break;
  1388. default: D3D12MA_ASSERT(0); break;
  1389. }
  1390. WriteString(L"Size");
  1391. WriteNumber(alloc.GetSize());
  1392. WriteString(L"Usage");
  1393. WriteNumber((UINT)alloc.m_PackedData.GetResourceFlags());
  1394. void* privateData = alloc.GetPrivateData();
  1395. if (privateData)
  1396. {
  1397. WriteString(L"CustomData");
  1398. BeginString();
  1399. ContinueString_Pointer(privateData);
  1400. EndString();
  1401. }
  1402. LPCWSTR name = alloc.GetName();
  1403. if (name != NULL)
  1404. {
  1405. WriteString(L"Name");
  1406. WriteString(name);
  1407. }
  1408. if (alloc.m_PackedData.GetTextureLayout())
  1409. {
  1410. WriteString(L"Layout");
  1411. WriteNumber((UINT)alloc.m_PackedData.GetTextureLayout());
  1412. }
  1413. }
  1414. void JsonWriter::AddDetailedStatisticsInfoObject(const DetailedStatistics& stats)
  1415. {
  1416. BeginObject();
  1417. WriteString(L"BlockCount");
  1418. WriteNumber(stats.Stats.BlockCount);
  1419. WriteString(L"BlockBytes");
  1420. WriteNumber(stats.Stats.BlockBytes);
  1421. WriteString(L"AllocationCount");
  1422. WriteNumber(stats.Stats.AllocationCount);
  1423. WriteString(L"AllocationBytes");
  1424. WriteNumber(stats.Stats.AllocationBytes);
  1425. WriteString(L"UnusedRangeCount");
  1426. WriteNumber(stats.UnusedRangeCount);
  1427. if (stats.Stats.AllocationCount > 1)
  1428. {
  1429. WriteString(L"AllocationSizeMin");
  1430. WriteNumber(stats.AllocationSizeMin);
  1431. WriteString(L"AllocationSizeMax");
  1432. WriteNumber(stats.AllocationSizeMax);
  1433. }
  1434. if (stats.UnusedRangeCount > 1)
  1435. {
  1436. WriteString(L"UnusedRangeSizeMin");
  1437. WriteNumber(stats.UnusedRangeSizeMin);
  1438. WriteString(L"UnusedRangeSizeMax");
  1439. WriteNumber(stats.UnusedRangeSizeMax);
  1440. }
  1441. EndObject();
  1442. }
  1443. void JsonWriter::BeginValue(bool isString)
  1444. {
  1445. if (!m_Stack.empty())
  1446. {
  1447. StackItem& currItem = m_Stack.back();
  1448. if (currItem.type == COLLECTION_TYPE_OBJECT && currItem.valueCount % 2 == 0)
  1449. {
  1450. D3D12MA_ASSERT(isString);
  1451. }
  1452. if (currItem.type == COLLECTION_TYPE_OBJECT && currItem.valueCount % 2 == 1)
  1453. {
  1454. m_SB.Add(L':'); m_SB.Add(L' ');
  1455. }
  1456. else if (currItem.valueCount > 0)
  1457. {
  1458. m_SB.Add(L','); m_SB.Add(L' ');
  1459. WriteIndent();
  1460. }
  1461. else
  1462. {
  1463. WriteIndent();
  1464. }
  1465. ++currItem.valueCount;
  1466. }
  1467. }
  1468. void JsonWriter::WriteIndent(bool oneLess)
  1469. {
  1470. if (!m_Stack.empty() && !m_Stack.back().singleLineMode)
  1471. {
  1472. m_SB.AddNewLine();
  1473. size_t count = m_Stack.size();
  1474. if (count > 0 && oneLess)
  1475. {
  1476. --count;
  1477. }
  1478. for (size_t i = 0; i < count; ++i)
  1479. {
  1480. m_SB.Add(INDENT);
  1481. }
  1482. }
  1483. }
  1484. #endif // _D3D12MA_JSON_WRITER_FUNCTIONS
  1485. #endif // _D3D12MA_JSON_WRITER
  1486. #ifndef _D3D12MA_POOL_ALLOCATOR
  1487. /*
  1488. Allocator for objects of type T using a list of arrays (pools) to speed up
  1489. allocation. Number of elements that can be allocated is not bounded because
  1490. allocator can create multiple blocks.
  1491. T should be POD because constructor and destructor is not called in Alloc or
  1492. Free.
  1493. */
  1494. template<typename T>
  1495. class PoolAllocator
  1496. {
  1497. D3D12MA_CLASS_NO_COPY(PoolAllocator)
  1498. public:
  1499. // allocationCallbacks externally owned, must outlive this object.
  1500. PoolAllocator(const ALLOCATION_CALLBACKS& allocationCallbacks, UINT firstBlockCapacity);
  1501. ~PoolAllocator() { Clear(); }
  1502. void Clear();
  1503. template<typename... Types>
  1504. T* Alloc(Types... args);
  1505. void Free(T* ptr);
  1506. private:
  1507. union Item
  1508. {
  1509. UINT NextFreeIndex; // UINT32_MAX means end of list.
  1510. alignas(T) char Value[sizeof(T)];
  1511. };
  1512. struct ItemBlock
  1513. {
  1514. Item* pItems;
  1515. UINT Capacity;
  1516. UINT FirstFreeIndex;
  1517. };
  1518. const ALLOCATION_CALLBACKS& m_AllocationCallbacks;
  1519. const UINT m_FirstBlockCapacity;
  1520. Vector<ItemBlock> m_ItemBlocks;
  1521. ItemBlock& CreateNewBlock();
  1522. };
  1523. #ifndef _D3D12MA_POOL_ALLOCATOR_FUNCTIONS
  1524. template<typename T>
  1525. PoolAllocator<T>::PoolAllocator(const ALLOCATION_CALLBACKS& allocationCallbacks, UINT firstBlockCapacity)
  1526. : m_AllocationCallbacks(allocationCallbacks),
  1527. m_FirstBlockCapacity(firstBlockCapacity),
  1528. m_ItemBlocks(allocationCallbacks)
  1529. {
  1530. D3D12MA_ASSERT(m_FirstBlockCapacity > 1);
  1531. }
  1532. template<typename T>
  1533. void PoolAllocator<T>::Clear()
  1534. {
  1535. for(size_t i = m_ItemBlocks.size(); i--; )
  1536. {
  1537. D3D12MA_DELETE_ARRAY(m_AllocationCallbacks, m_ItemBlocks[i].pItems, m_ItemBlocks[i].Capacity);
  1538. }
  1539. m_ItemBlocks.clear(true);
  1540. }
  1541. template<typename T> template<typename... Types>
  1542. T* PoolAllocator<T>::Alloc(Types... args)
  1543. {
  1544. for(size_t i = m_ItemBlocks.size(); i--; )
  1545. {
  1546. ItemBlock& block = m_ItemBlocks[i];
  1547. // This block has some free items: Use first one.
  1548. if(block.FirstFreeIndex != UINT32_MAX)
  1549. {
  1550. Item* const pItem = &block.pItems[block.FirstFreeIndex];
  1551. block.FirstFreeIndex = pItem->NextFreeIndex;
  1552. T* result = (T*)&pItem->Value;
  1553. new(result)T(std::forward<Types>(args)...); // Explicit constructor call.
  1554. return result;
  1555. }
  1556. }
  1557. // No block has free item: Create new one and use it.
  1558. ItemBlock& newBlock = CreateNewBlock();
  1559. Item* const pItem = &newBlock.pItems[0];
  1560. newBlock.FirstFreeIndex = pItem->NextFreeIndex;
  1561. T* result = (T*)pItem->Value;
  1562. new(result)T(std::forward<Types>(args)...); // Explicit constructor call.
  1563. return result;
  1564. }
  1565. template<typename T>
  1566. void PoolAllocator<T>::Free(T* ptr)
  1567. {
  1568. // Search all memory blocks to find ptr.
  1569. for(size_t i = m_ItemBlocks.size(); i--; )
  1570. {
  1571. ItemBlock& block = m_ItemBlocks[i];
  1572. Item* pItemPtr;
  1573. memcpy(&pItemPtr, &ptr, sizeof(pItemPtr));
  1574. // Check if pItemPtr is in address range of this block.
  1575. if((pItemPtr >= block.pItems) && (pItemPtr < block.pItems + block.Capacity))
  1576. {
  1577. ptr->~T(); // Explicit destructor call.
  1578. const UINT index = static_cast<UINT>(pItemPtr - block.pItems);
  1579. pItemPtr->NextFreeIndex = block.FirstFreeIndex;
  1580. block.FirstFreeIndex = index;
  1581. return;
  1582. }
  1583. }
  1584. D3D12MA_ASSERT(0 && "Pointer doesn't belong to this memory pool.");
  1585. }
  1586. template<typename T>
  1587. typename PoolAllocator<T>::ItemBlock& PoolAllocator<T>::CreateNewBlock()
  1588. {
  1589. const UINT newBlockCapacity = m_ItemBlocks.empty() ?
  1590. m_FirstBlockCapacity : m_ItemBlocks.back().Capacity * 3 / 2;
  1591. const ItemBlock newBlock = {
  1592. D3D12MA_NEW_ARRAY(m_AllocationCallbacks, Item, newBlockCapacity),
  1593. newBlockCapacity,
  1594. 0 };
  1595. m_ItemBlocks.push_back(newBlock);
  1596. // Setup singly-linked list of all free items in this block.
  1597. for(UINT i = 0; i < newBlockCapacity - 1; ++i)
  1598. {
  1599. newBlock.pItems[i].NextFreeIndex = i + 1;
  1600. }
  1601. newBlock.pItems[newBlockCapacity - 1].NextFreeIndex = UINT32_MAX;
  1602. return m_ItemBlocks.back();
  1603. }
  1604. #endif // _D3D12MA_POOL_ALLOCATOR_FUNCTIONS
  1605. #endif // _D3D12MA_POOL_ALLOCATOR
  1606. #ifndef _D3D12MA_LIST
  1607. /*
  1608. Doubly linked list, with elements allocated out of PoolAllocator.
  1609. Has custom interface, as well as STL-style interface, including iterator and
  1610. const_iterator.
  1611. */
  1612. template<typename T>
  1613. class List
  1614. {
  1615. D3D12MA_CLASS_NO_COPY(List)
  1616. public:
  1617. struct Item
  1618. {
  1619. Item* pPrev;
  1620. Item* pNext;
  1621. T Value;
  1622. };
  1623. class reverse_iterator;
  1624. class const_reverse_iterator;
  1625. class iterator
  1626. {
  1627. friend class List<T>;
  1628. friend class const_iterator;
  1629. public:
  1630. iterator() = default;
  1631. iterator(const reverse_iterator& src)
  1632. : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
  1633. T& operator*() const;
  1634. T* operator->() const;
  1635. iterator& operator++();
  1636. iterator& operator--();
  1637. iterator operator++(int);
  1638. iterator operator--(int);
  1639. bool operator==(const iterator& rhs) const;
  1640. bool operator!=(const iterator& rhs) const;
  1641. private:
  1642. List<T>* m_pList = NULL;
  1643. Item* m_pItem = NULL;
  1644. iterator(List<T>* pList, Item* pItem) : m_pList(pList), m_pItem(pItem) {}
  1645. };
  1646. class reverse_iterator
  1647. {
  1648. friend class List<T>;
  1649. friend class const_reverse_iterator;
  1650. public:
  1651. reverse_iterator() = default;
  1652. reverse_iterator(const iterator& src)
  1653. : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
  1654. T& operator*() const;
  1655. T* operator->() const;
  1656. reverse_iterator& operator++();
  1657. reverse_iterator& operator--();
  1658. reverse_iterator operator++(int);
  1659. reverse_iterator operator--(int);
  1660. bool operator==(const reverse_iterator& rhs) const;
  1661. bool operator!=(const reverse_iterator& rhs) const;
  1662. private:
  1663. List<T>* m_pList = NULL;
  1664. Item* m_pItem = NULL;
  1665. reverse_iterator(List<T>* pList, Item* pItem)
  1666. : m_pList(pList), m_pItem(pItem) {}
  1667. };
  1668. class const_iterator
  1669. {
  1670. friend class List<T>;
  1671. public:
  1672. const_iterator() = default;
  1673. const_iterator(const iterator& src)
  1674. : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
  1675. const_iterator(const reverse_iterator& src)
  1676. : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
  1677. const_iterator(const const_reverse_iterator& src)
  1678. : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
  1679. iterator dropConst() const;
  1680. const T& operator*() const;
  1681. const T* operator->() const;
  1682. const_iterator& operator++();
  1683. const_iterator& operator--();
  1684. const_iterator operator++(int);
  1685. const_iterator operator--(int);
  1686. bool operator==(const const_iterator& rhs) const;
  1687. bool operator!=(const const_iterator& rhs) const;
  1688. private:
  1689. const List<T>* m_pList = NULL;
  1690. const Item* m_pItem = NULL;
  1691. const_iterator(const List<T>* pList, const Item* pItem)
  1692. : m_pList(pList), m_pItem(pItem) {}
  1693. };
  1694. class const_reverse_iterator
  1695. {
  1696. friend class List<T>;
  1697. public:
  1698. const_reverse_iterator() = default;
  1699. const_reverse_iterator(const iterator& src)
  1700. : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
  1701. const_reverse_iterator(const reverse_iterator& src)
  1702. : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
  1703. const_reverse_iterator(const const_iterator& src)
  1704. : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
  1705. reverse_iterator dropConst() const;
  1706. const T& operator*() const;
  1707. const T* operator->() const;
  1708. const_reverse_iterator& operator++();
  1709. const_reverse_iterator& operator--();
  1710. const_reverse_iterator operator++(int);
  1711. const_reverse_iterator operator--(int);
  1712. bool operator==(const const_reverse_iterator& rhs) const;
  1713. bool operator!=(const const_reverse_iterator& rhs) const;
  1714. private:
  1715. const List<T>* m_pList = NULL;
  1716. const Item* m_pItem = NULL;
  1717. const_reverse_iterator(const List<T>* pList, const Item* pItem)
  1718. : m_pList(pList), m_pItem(pItem) {}
  1719. };
  1720. // allocationCallbacks externally owned, must outlive this object.
  1721. List(const ALLOCATION_CALLBACKS& allocationCallbacks);
  1722. // Intentionally not calling Clear, because that would be unnecessary
  1723. // computations to return all items to m_ItemAllocator as free.
  1724. ~List() = default;
  1725. size_t GetCount() const { return m_Count; }
  1726. bool IsEmpty() const { return m_Count == 0; }
  1727. Item* Front() { return m_pFront; }
  1728. const Item* Front() const { return m_pFront; }
  1729. Item* Back() { return m_pBack; }
  1730. const Item* Back() const { return m_pBack; }
  1731. bool empty() const { return IsEmpty(); }
  1732. size_t size() const { return GetCount(); }
  1733. void push_back(const T& value) { PushBack(value); }
  1734. iterator insert(iterator it, const T& value) { return iterator(this, InsertBefore(it.m_pItem, value)); }
  1735. void clear() { Clear(); }
  1736. void erase(iterator it) { Remove(it.m_pItem); }
  1737. iterator begin() { return iterator(this, Front()); }
  1738. iterator end() { return iterator(this, NULL); }
  1739. reverse_iterator rbegin() { return reverse_iterator(this, Back()); }
  1740. reverse_iterator rend() { return reverse_iterator(this, NULL); }
  1741. const_iterator cbegin() const { return const_iterator(this, Front()); }
  1742. const_iterator cend() const { return const_iterator(this, NULL); }
  1743. const_iterator begin() const { return cbegin(); }
  1744. const_iterator end() const { return cend(); }
  1745. const_reverse_iterator crbegin() const { return const_reverse_iterator(this, Back()); }
  1746. const_reverse_iterator crend() const { return const_reverse_iterator(this, NULL); }
  1747. const_reverse_iterator rbegin() const { return crbegin(); }
  1748. const_reverse_iterator rend() const { return crend(); }
  1749. Item* PushBack();
  1750. Item* PushFront();
  1751. Item* PushBack(const T& value);
  1752. Item* PushFront(const T& value);
  1753. void PopBack();
  1754. void PopFront();
  1755. // Item can be null - it means PushBack.
  1756. Item* InsertBefore(Item* pItem);
  1757. // Item can be null - it means PushFront.
  1758. Item* InsertAfter(Item* pItem);
  1759. Item* InsertBefore(Item* pItem, const T& value);
  1760. Item* InsertAfter(Item* pItem, const T& value);
  1761. void Clear();
  1762. void Remove(Item* pItem);
  1763. private:
  1764. const ALLOCATION_CALLBACKS& m_AllocationCallbacks;
  1765. PoolAllocator<Item> m_ItemAllocator;
  1766. Item* m_pFront;
  1767. Item* m_pBack;
  1768. size_t m_Count;
  1769. };
  1770. #ifndef _D3D12MA_LIST_ITERATOR_FUNCTIONS
  1771. template<typename T>
  1772. T& List<T>::iterator::operator*() const
  1773. {
  1774. D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
  1775. return m_pItem->Value;
  1776. }
  1777. template<typename T>
  1778. T* List<T>::iterator::operator->() const
  1779. {
  1780. D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
  1781. return &m_pItem->Value;
  1782. }
  1783. template<typename T>
  1784. typename List<T>::iterator& List<T>::iterator::operator++()
  1785. {
  1786. D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
  1787. m_pItem = m_pItem->pNext;
  1788. return *this;
  1789. }
  1790. template<typename T>
  1791. typename List<T>::iterator& List<T>::iterator::operator--()
  1792. {
  1793. if (m_pItem != NULL)
  1794. {
  1795. m_pItem = m_pItem->pPrev;
  1796. }
  1797. else
  1798. {
  1799. D3D12MA_HEAVY_ASSERT(!m_pList->IsEmpty());
  1800. m_pItem = m_pList->Back();
  1801. }
  1802. return *this;
  1803. }
  1804. template<typename T>
  1805. typename List<T>::iterator List<T>::iterator::operator++(int)
  1806. {
  1807. iterator result = *this;
  1808. ++* this;
  1809. return result;
  1810. }
  1811. template<typename T>
  1812. typename List<T>::iterator List<T>::iterator::operator--(int)
  1813. {
  1814. iterator result = *this;
  1815. --* this;
  1816. return result;
  1817. }
  1818. template<typename T>
  1819. bool List<T>::iterator::operator==(const iterator& rhs) const
  1820. {
  1821. D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
  1822. return m_pItem == rhs.m_pItem;
  1823. }
  1824. template<typename T>
  1825. bool List<T>::iterator::operator!=(const iterator& rhs) const
  1826. {
  1827. D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
  1828. return m_pItem != rhs.m_pItem;
  1829. }
  1830. #endif // _D3D12MA_LIST_ITERATOR_FUNCTIONS
  1831. #ifndef _D3D12MA_LIST_REVERSE_ITERATOR_FUNCTIONS
  1832. template<typename T>
  1833. T& List<T>::reverse_iterator::operator*() const
  1834. {
  1835. D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
  1836. return m_pItem->Value;
  1837. }
  1838. template<typename T>
  1839. T* List<T>::reverse_iterator::operator->() const
  1840. {
  1841. D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
  1842. return &m_pItem->Value;
  1843. }
  1844. template<typename T>
  1845. typename List<T>::reverse_iterator& List<T>::reverse_iterator::operator++()
  1846. {
  1847. D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
  1848. m_pItem = m_pItem->pPrev;
  1849. return *this;
  1850. }
  1851. template<typename T>
  1852. typename List<T>::reverse_iterator& List<T>::reverse_iterator::operator--()
  1853. {
  1854. if (m_pItem != NULL)
  1855. {
  1856. m_pItem = m_pItem->pNext;
  1857. }
  1858. else
  1859. {
  1860. D3D12MA_HEAVY_ASSERT(!m_pList->IsEmpty());
  1861. m_pItem = m_pList->Front();
  1862. }
  1863. return *this;
  1864. }
  1865. template<typename T>
  1866. typename List<T>::reverse_iterator List<T>::reverse_iterator::operator++(int)
  1867. {
  1868. reverse_iterator result = *this;
  1869. ++* this;
  1870. return result;
  1871. }
  1872. template<typename T>
  1873. typename List<T>::reverse_iterator List<T>::reverse_iterator::operator--(int)
  1874. {
  1875. reverse_iterator result = *this;
  1876. --* this;
  1877. return result;
  1878. }
  1879. template<typename T>
  1880. bool List<T>::reverse_iterator::operator==(const reverse_iterator& rhs) const
  1881. {
  1882. D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
  1883. return m_pItem == rhs.m_pItem;
  1884. }
  1885. template<typename T>
  1886. bool List<T>::reverse_iterator::operator!=(const reverse_iterator& rhs) const
  1887. {
  1888. D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
  1889. return m_pItem != rhs.m_pItem;
  1890. }
  1891. #endif // _D3D12MA_LIST_REVERSE_ITERATOR_FUNCTIONS
  1892. #ifndef _D3D12MA_LIST_CONST_ITERATOR_FUNCTIONS
  1893. template<typename T>
  1894. typename List<T>::iterator List<T>::const_iterator::dropConst() const
  1895. {
  1896. return iterator(const_cast<List<T>*>(m_pList), const_cast<Item*>(m_pItem));
  1897. }
  1898. template<typename T>
  1899. const T& List<T>::const_iterator::operator*() const
  1900. {
  1901. D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
  1902. return m_pItem->Value;
  1903. }
  1904. template<typename T>
  1905. const T* List<T>::const_iterator::operator->() const
  1906. {
  1907. D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
  1908. return &m_pItem->Value;
  1909. }
  1910. template<typename T>
  1911. typename List<T>::const_iterator& List<T>::const_iterator::operator++()
  1912. {
  1913. D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
  1914. m_pItem = m_pItem->pNext;
  1915. return *this;
  1916. }
  1917. template<typename T>
  1918. typename List<T>::const_iterator& List<T>::const_iterator::operator--()
  1919. {
  1920. if (m_pItem != NULL)
  1921. {
  1922. m_pItem = m_pItem->pPrev;
  1923. }
  1924. else
  1925. {
  1926. D3D12MA_HEAVY_ASSERT(!m_pList->IsEmpty());
  1927. m_pItem = m_pList->Back();
  1928. }
  1929. return *this;
  1930. }
  1931. template<typename T>
  1932. typename List<T>::const_iterator List<T>::const_iterator::operator++(int)
  1933. {
  1934. const_iterator result = *this;
  1935. ++* this;
  1936. return result;
  1937. }
  1938. template<typename T>
  1939. typename List<T>::const_iterator List<T>::const_iterator::operator--(int)
  1940. {
  1941. const_iterator result = *this;
  1942. --* this;
  1943. return result;
  1944. }
  1945. template<typename T>
  1946. bool List<T>::const_iterator::operator==(const const_iterator& rhs) const
  1947. {
  1948. D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
  1949. return m_pItem == rhs.m_pItem;
  1950. }
  1951. template<typename T>
  1952. bool List<T>::const_iterator::operator!=(const const_iterator& rhs) const
  1953. {
  1954. D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
  1955. return m_pItem != rhs.m_pItem;
  1956. }
  1957. #endif // _D3D12MA_LIST_CONST_ITERATOR_FUNCTIONS
  1958. #ifndef _D3D12MA_LIST_CONST_REVERSE_ITERATOR_FUNCTIONS
  1959. template<typename T>
  1960. typename List<T>::reverse_iterator List<T>::const_reverse_iterator::dropConst() const
  1961. {
  1962. return reverse_iterator(const_cast<List<T>*>(m_pList), const_cast<Item*>(m_pItem));
  1963. }
  1964. template<typename T>
  1965. const T& List<T>::const_reverse_iterator::operator*() const
  1966. {
  1967. D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
  1968. return m_pItem->Value;
  1969. }
  1970. template<typename T>
  1971. const T* List<T>::const_reverse_iterator::operator->() const
  1972. {
  1973. D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
  1974. return &m_pItem->Value;
  1975. }
  1976. template<typename T>
  1977. typename List<T>::const_reverse_iterator& List<T>::const_reverse_iterator::operator++()
  1978. {
  1979. D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
  1980. m_pItem = m_pItem->pPrev;
  1981. return *this;
  1982. }
  1983. template<typename T>
  1984. typename List<T>::const_reverse_iterator& List<T>::const_reverse_iterator::operator--()
  1985. {
  1986. if (m_pItem != NULL)
  1987. {
  1988. m_pItem = m_pItem->pNext;
  1989. }
  1990. else
  1991. {
  1992. D3D12MA_HEAVY_ASSERT(!m_pList->IsEmpty());
  1993. m_pItem = m_pList->Front();
  1994. }
  1995. return *this;
  1996. }
  1997. template<typename T>
  1998. typename List<T>::const_reverse_iterator List<T>::const_reverse_iterator::operator++(int)
  1999. {
  2000. const_reverse_iterator result = *this;
  2001. ++* this;
  2002. return result;
  2003. }
  2004. template<typename T>
  2005. typename List<T>::const_reverse_iterator List<T>::const_reverse_iterator::operator--(int)
  2006. {
  2007. const_reverse_iterator result = *this;
  2008. --* this;
  2009. return result;
  2010. }
  2011. template<typename T>
  2012. bool List<T>::const_reverse_iterator::operator==(const const_reverse_iterator& rhs) const
  2013. {
  2014. D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
  2015. return m_pItem == rhs.m_pItem;
  2016. }
  2017. template<typename T>
  2018. bool List<T>::const_reverse_iterator::operator!=(const const_reverse_iterator& rhs) const
  2019. {
  2020. D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
  2021. return m_pItem != rhs.m_pItem;
  2022. }
  2023. #endif // _D3D12MA_LIST_CONST_REVERSE_ITERATOR_FUNCTIONS
  2024. #ifndef _D3D12MA_LIST_FUNCTIONS
  2025. template<typename T>
  2026. List<T>::List(const ALLOCATION_CALLBACKS& allocationCallbacks)
  2027. : m_AllocationCallbacks(allocationCallbacks),
  2028. m_ItemAllocator(allocationCallbacks, 128),
  2029. m_pFront(NULL),
  2030. m_pBack(NULL),
  2031. m_Count(0) {}
  2032. template<typename T>
  2033. void List<T>::Clear()
  2034. {
  2035. if(!IsEmpty())
  2036. {
  2037. Item* pItem = m_pBack;
  2038. while(pItem != NULL)
  2039. {
  2040. Item* const pPrevItem = pItem->pPrev;
  2041. m_ItemAllocator.Free(pItem);
  2042. pItem = pPrevItem;
  2043. }
  2044. m_pFront = NULL;
  2045. m_pBack = NULL;
  2046. m_Count = 0;
  2047. }
  2048. }
  2049. template<typename T>
  2050. typename List<T>::Item* List<T>::PushBack()
  2051. {
  2052. Item* const pNewItem = m_ItemAllocator.Alloc();
  2053. pNewItem->pNext = NULL;
  2054. if(IsEmpty())
  2055. {
  2056. pNewItem->pPrev = NULL;
  2057. m_pFront = pNewItem;
  2058. m_pBack = pNewItem;
  2059. m_Count = 1;
  2060. }
  2061. else
  2062. {
  2063. pNewItem->pPrev = m_pBack;
  2064. m_pBack->pNext = pNewItem;
  2065. m_pBack = pNewItem;
  2066. ++m_Count;
  2067. }
  2068. return pNewItem;
  2069. }
  2070. template<typename T>
  2071. typename List<T>::Item* List<T>::PushFront()
  2072. {
  2073. Item* const pNewItem = m_ItemAllocator.Alloc();
  2074. pNewItem->pPrev = NULL;
  2075. if(IsEmpty())
  2076. {
  2077. pNewItem->pNext = NULL;
  2078. m_pFront = pNewItem;
  2079. m_pBack = pNewItem;
  2080. m_Count = 1;
  2081. }
  2082. else
  2083. {
  2084. pNewItem->pNext = m_pFront;
  2085. m_pFront->pPrev = pNewItem;
  2086. m_pFront = pNewItem;
  2087. ++m_Count;
  2088. }
  2089. return pNewItem;
  2090. }
  2091. template<typename T>
  2092. typename List<T>::Item* List<T>::PushBack(const T& value)
  2093. {
  2094. Item* const pNewItem = PushBack();
  2095. pNewItem->Value = value;
  2096. return pNewItem;
  2097. }
  2098. template<typename T>
  2099. typename List<T>::Item* List<T>::PushFront(const T& value)
  2100. {
  2101. Item* const pNewItem = PushFront();
  2102. pNewItem->Value = value;
  2103. return pNewItem;
  2104. }
  2105. template<typename T>
  2106. void List<T>::PopBack()
  2107. {
  2108. D3D12MA_HEAVY_ASSERT(m_Count > 0);
  2109. Item* const pBackItem = m_pBack;
  2110. Item* const pPrevItem = pBackItem->pPrev;
  2111. if(pPrevItem != NULL)
  2112. {
  2113. pPrevItem->pNext = NULL;
  2114. }
  2115. m_pBack = pPrevItem;
  2116. m_ItemAllocator.Free(pBackItem);
  2117. --m_Count;
  2118. }
  2119. template<typename T>
  2120. void List<T>::PopFront()
  2121. {
  2122. D3D12MA_HEAVY_ASSERT(m_Count > 0);
  2123. Item* const pFrontItem = m_pFront;
  2124. Item* const pNextItem = pFrontItem->pNext;
  2125. if(pNextItem != NULL)
  2126. {
  2127. pNextItem->pPrev = NULL;
  2128. }
  2129. m_pFront = pNextItem;
  2130. m_ItemAllocator.Free(pFrontItem);
  2131. --m_Count;
  2132. }
  2133. template<typename T>
  2134. void List<T>::Remove(Item* pItem)
  2135. {
  2136. D3D12MA_HEAVY_ASSERT(pItem != NULL);
  2137. D3D12MA_HEAVY_ASSERT(m_Count > 0);
  2138. if(pItem->pPrev != NULL)
  2139. {
  2140. pItem->pPrev->pNext = pItem->pNext;
  2141. }
  2142. else
  2143. {
  2144. D3D12MA_HEAVY_ASSERT(m_pFront == pItem);
  2145. m_pFront = pItem->pNext;
  2146. }
  2147. if(pItem->pNext != NULL)
  2148. {
  2149. pItem->pNext->pPrev = pItem->pPrev;
  2150. }
  2151. else
  2152. {
  2153. D3D12MA_HEAVY_ASSERT(m_pBack == pItem);
  2154. m_pBack = pItem->pPrev;
  2155. }
  2156. m_ItemAllocator.Free(pItem);
  2157. --m_Count;
  2158. }
  2159. template<typename T>
  2160. typename List<T>::Item* List<T>::InsertBefore(Item* pItem)
  2161. {
  2162. if(pItem != NULL)
  2163. {
  2164. Item* const prevItem = pItem->pPrev;
  2165. Item* const newItem = m_ItemAllocator.Alloc();
  2166. newItem->pPrev = prevItem;
  2167. newItem->pNext = pItem;
  2168. pItem->pPrev = newItem;
  2169. if(prevItem != NULL)
  2170. {
  2171. prevItem->pNext = newItem;
  2172. }
  2173. else
  2174. {
  2175. D3D12MA_HEAVY_ASSERT(m_pFront == pItem);
  2176. m_pFront = newItem;
  2177. }
  2178. ++m_Count;
  2179. return newItem;
  2180. }
  2181. else
  2182. {
  2183. return PushBack();
  2184. }
  2185. }
  2186. template<typename T>
  2187. typename List<T>::Item* List<T>::InsertAfter(Item* pItem)
  2188. {
  2189. if(pItem != NULL)
  2190. {
  2191. Item* const nextItem = pItem->pNext;
  2192. Item* const newItem = m_ItemAllocator.Alloc();
  2193. newItem->pNext = nextItem;
  2194. newItem->pPrev = pItem;
  2195. pItem->pNext = newItem;
  2196. if(nextItem != NULL)
  2197. {
  2198. nextItem->pPrev = newItem;
  2199. }
  2200. else
  2201. {
  2202. D3D12MA_HEAVY_ASSERT(m_pBack == pItem);
  2203. m_pBack = newItem;
  2204. }
  2205. ++m_Count;
  2206. return newItem;
  2207. }
  2208. else
  2209. return PushFront();
  2210. }
  2211. template<typename T>
  2212. typename List<T>::Item* List<T>::InsertBefore(Item* pItem, const T& value)
  2213. {
  2214. Item* const newItem = InsertBefore(pItem);
  2215. newItem->Value = value;
  2216. return newItem;
  2217. }
  2218. template<typename T>
  2219. typename List<T>::Item* List<T>::InsertAfter(Item* pItem, const T& value)
  2220. {
  2221. Item* const newItem = InsertAfter(pItem);
  2222. newItem->Value = value;
  2223. return newItem;
  2224. }
  2225. #endif // _D3D12MA_LIST_FUNCTIONS
  2226. #endif // _D3D12MA_LIST
  2227. #ifndef _D3D12MA_INTRUSIVE_LINKED_LIST
  2228. /*
  2229. Expected interface of ItemTypeTraits:
  2230. struct MyItemTypeTraits
  2231. {
  2232. using ItemType = MyItem;
  2233. static ItemType* GetPrev(const ItemType* item) { return item->myPrevPtr; }
  2234. static ItemType* GetNext(const ItemType* item) { return item->myNextPtr; }
  2235. static ItemType*& AccessPrev(ItemType* item) { return item->myPrevPtr; }
  2236. static ItemType*& AccessNext(ItemType* item) { return item->myNextPtr; }
  2237. };
  2238. */
  2239. template<typename ItemTypeTraits>
  2240. class IntrusiveLinkedList
  2241. {
  2242. public:
  2243. using ItemType = typename ItemTypeTraits::ItemType;
  2244. static ItemType* GetPrev(const ItemType* item) { return ItemTypeTraits::GetPrev(item); }
  2245. static ItemType* GetNext(const ItemType* item) { return ItemTypeTraits::GetNext(item); }
  2246. // Movable, not copyable.
  2247. IntrusiveLinkedList() = default;
  2248. IntrusiveLinkedList(const IntrusiveLinkedList&) = delete;
  2249. IntrusiveLinkedList(IntrusiveLinkedList&& src);
  2250. IntrusiveLinkedList& operator=(const IntrusiveLinkedList&) = delete;
  2251. IntrusiveLinkedList& operator=(IntrusiveLinkedList&& src);
  2252. ~IntrusiveLinkedList() { D3D12MA_HEAVY_ASSERT(IsEmpty()); }
  2253. size_t GetCount() const { return m_Count; }
  2254. bool IsEmpty() const { return m_Count == 0; }
  2255. ItemType* Front() { return m_Front; }
  2256. ItemType* Back() { return m_Back; }
  2257. const ItemType* Front() const { return m_Front; }
  2258. const ItemType* Back() const { return m_Back; }
  2259. void PushBack(ItemType* item);
  2260. void PushFront(ItemType* item);
  2261. ItemType* PopBack();
  2262. ItemType* PopFront();
  2263. // MyItem can be null - it means PushBack.
  2264. void InsertBefore(ItemType* existingItem, ItemType* newItem);
  2265. // MyItem can be null - it means PushFront.
  2266. void InsertAfter(ItemType* existingItem, ItemType* newItem);
  2267. void Remove(ItemType* item);
  2268. void RemoveAll();
  2269. private:
  2270. ItemType* m_Front = NULL;
  2271. ItemType* m_Back = NULL;
  2272. size_t m_Count = 0;
  2273. };
  2274. #ifndef _D3D12MA_INTRUSIVE_LINKED_LIST_FUNCTIONS
  2275. template<typename ItemTypeTraits>
  2276. IntrusiveLinkedList<ItemTypeTraits>::IntrusiveLinkedList(IntrusiveLinkedList&& src)
  2277. : m_Front(src.m_Front), m_Back(src.m_Back), m_Count(src.m_Count)
  2278. {
  2279. src.m_Front = src.m_Back = NULL;
  2280. src.m_Count = 0;
  2281. }
  2282. template<typename ItemTypeTraits>
  2283. IntrusiveLinkedList<ItemTypeTraits>& IntrusiveLinkedList<ItemTypeTraits>::operator=(IntrusiveLinkedList&& src)
  2284. {
  2285. if (&src != this)
  2286. {
  2287. D3D12MA_HEAVY_ASSERT(IsEmpty());
  2288. m_Front = src.m_Front;
  2289. m_Back = src.m_Back;
  2290. m_Count = src.m_Count;
  2291. src.m_Front = src.m_Back = NULL;
  2292. src.m_Count = 0;
  2293. }
  2294. return *this;
  2295. }
  2296. template<typename ItemTypeTraits>
  2297. void IntrusiveLinkedList<ItemTypeTraits>::PushBack(ItemType* item)
  2298. {
  2299. D3D12MA_HEAVY_ASSERT(ItemTypeTraits::GetPrev(item) == NULL && ItemTypeTraits::GetNext(item) == NULL);
  2300. if (IsEmpty())
  2301. {
  2302. m_Front = item;
  2303. m_Back = item;
  2304. m_Count = 1;
  2305. }
  2306. else
  2307. {
  2308. ItemTypeTraits::AccessPrev(item) = m_Back;
  2309. ItemTypeTraits::AccessNext(m_Back) = item;
  2310. m_Back = item;
  2311. ++m_Count;
  2312. }
  2313. }
  2314. template<typename ItemTypeTraits>
  2315. void IntrusiveLinkedList<ItemTypeTraits>::PushFront(ItemType* item)
  2316. {
  2317. D3D12MA_HEAVY_ASSERT(ItemTypeTraits::GetPrev(item) == NULL && ItemTypeTraits::GetNext(item) == NULL);
  2318. if (IsEmpty())
  2319. {
  2320. m_Front = item;
  2321. m_Back = item;
  2322. m_Count = 1;
  2323. }
  2324. else
  2325. {
  2326. ItemTypeTraits::AccessNext(item) = m_Front;
  2327. ItemTypeTraits::AccessPrev(m_Front) = item;
  2328. m_Front = item;
  2329. ++m_Count;
  2330. }
  2331. }
  2332. template<typename ItemTypeTraits>
  2333. typename IntrusiveLinkedList<ItemTypeTraits>::ItemType* IntrusiveLinkedList<ItemTypeTraits>::PopBack()
  2334. {
  2335. D3D12MA_HEAVY_ASSERT(m_Count > 0);
  2336. ItemType* const backItem = m_Back;
  2337. ItemType* const prevItem = ItemTypeTraits::GetPrev(backItem);
  2338. if (prevItem != NULL)
  2339. {
  2340. ItemTypeTraits::AccessNext(prevItem) = NULL;
  2341. }
  2342. m_Back = prevItem;
  2343. --m_Count;
  2344. ItemTypeTraits::AccessPrev(backItem) = NULL;
  2345. ItemTypeTraits::AccessNext(backItem) = NULL;
  2346. return backItem;
  2347. }
  2348. template<typename ItemTypeTraits>
  2349. typename IntrusiveLinkedList<ItemTypeTraits>::ItemType* IntrusiveLinkedList<ItemTypeTraits>::PopFront()
  2350. {
  2351. D3D12MA_HEAVY_ASSERT(m_Count > 0);
  2352. ItemType* const frontItem = m_Front;
  2353. ItemType* const nextItem = ItemTypeTraits::GetNext(frontItem);
  2354. if (nextItem != NULL)
  2355. {
  2356. ItemTypeTraits::AccessPrev(nextItem) = NULL;
  2357. }
  2358. m_Front = nextItem;
  2359. --m_Count;
  2360. ItemTypeTraits::AccessPrev(frontItem) = NULL;
  2361. ItemTypeTraits::AccessNext(frontItem) = NULL;
  2362. return frontItem;
  2363. }
  2364. template<typename ItemTypeTraits>
  2365. void IntrusiveLinkedList<ItemTypeTraits>::InsertBefore(ItemType* existingItem, ItemType* newItem)
  2366. {
  2367. D3D12MA_HEAVY_ASSERT(newItem != NULL && ItemTypeTraits::GetPrev(newItem) == NULL && ItemTypeTraits::GetNext(newItem) == NULL);
  2368. if (existingItem != NULL)
  2369. {
  2370. ItemType* const prevItem = ItemTypeTraits::GetPrev(existingItem);
  2371. ItemTypeTraits::AccessPrev(newItem) = prevItem;
  2372. ItemTypeTraits::AccessNext(newItem) = existingItem;
  2373. ItemTypeTraits::AccessPrev(existingItem) = newItem;
  2374. if (prevItem != NULL)
  2375. {
  2376. ItemTypeTraits::AccessNext(prevItem) = newItem;
  2377. }
  2378. else
  2379. {
  2380. D3D12MA_HEAVY_ASSERT(m_Front == existingItem);
  2381. m_Front = newItem;
  2382. }
  2383. ++m_Count;
  2384. }
  2385. else
  2386. PushBack(newItem);
  2387. }
  2388. template<typename ItemTypeTraits>
  2389. void IntrusiveLinkedList<ItemTypeTraits>::InsertAfter(ItemType* existingItem, ItemType* newItem)
  2390. {
  2391. D3D12MA_HEAVY_ASSERT(newItem != NULL && ItemTypeTraits::GetPrev(newItem) == NULL && ItemTypeTraits::GetNext(newItem) == NULL);
  2392. if (existingItem != NULL)
  2393. {
  2394. ItemType* const nextItem = ItemTypeTraits::GetNext(existingItem);
  2395. ItemTypeTraits::AccessNext(newItem) = nextItem;
  2396. ItemTypeTraits::AccessPrev(newItem) = existingItem;
  2397. ItemTypeTraits::AccessNext(existingItem) = newItem;
  2398. if (nextItem != NULL)
  2399. {
  2400. ItemTypeTraits::AccessPrev(nextItem) = newItem;
  2401. }
  2402. else
  2403. {
  2404. D3D12MA_HEAVY_ASSERT(m_Back == existingItem);
  2405. m_Back = newItem;
  2406. }
  2407. ++m_Count;
  2408. }
  2409. else
  2410. return PushFront(newItem);
  2411. }
  2412. template<typename ItemTypeTraits>
  2413. void IntrusiveLinkedList<ItemTypeTraits>::Remove(ItemType* item)
  2414. {
  2415. D3D12MA_HEAVY_ASSERT(item != NULL && m_Count > 0);
  2416. if (ItemTypeTraits::GetPrev(item) != NULL)
  2417. {
  2418. ItemTypeTraits::AccessNext(ItemTypeTraits::AccessPrev(item)) = ItemTypeTraits::GetNext(item);
  2419. }
  2420. else
  2421. {
  2422. D3D12MA_HEAVY_ASSERT(m_Front == item);
  2423. m_Front = ItemTypeTraits::GetNext(item);
  2424. }
  2425. if (ItemTypeTraits::GetNext(item) != NULL)
  2426. {
  2427. ItemTypeTraits::AccessPrev(ItemTypeTraits::AccessNext(item)) = ItemTypeTraits::GetPrev(item);
  2428. }
  2429. else
  2430. {
  2431. D3D12MA_HEAVY_ASSERT(m_Back == item);
  2432. m_Back = ItemTypeTraits::GetPrev(item);
  2433. }
  2434. ItemTypeTraits::AccessPrev(item) = NULL;
  2435. ItemTypeTraits::AccessNext(item) = NULL;
  2436. --m_Count;
  2437. }
  2438. template<typename ItemTypeTraits>
  2439. void IntrusiveLinkedList<ItemTypeTraits>::RemoveAll()
  2440. {
  2441. if (!IsEmpty())
  2442. {
  2443. ItemType* item = m_Back;
  2444. while (item != NULL)
  2445. {
  2446. ItemType* const prevItem = ItemTypeTraits::AccessPrev(item);
  2447. ItemTypeTraits::AccessPrev(item) = NULL;
  2448. ItemTypeTraits::AccessNext(item) = NULL;
  2449. item = prevItem;
  2450. }
  2451. m_Front = NULL;
  2452. m_Back = NULL;
  2453. m_Count = 0;
  2454. }
  2455. }
  2456. #endif // _D3D12MA_INTRUSIVE_LINKED_LIST_FUNCTIONS
  2457. #endif // _D3D12MA_INTRUSIVE_LINKED_LIST
  2458. #ifndef _D3D12MA_ALLOCATION_OBJECT_ALLOCATOR
  2459. /*
  2460. Thread-safe wrapper over PoolAllocator free list, for allocation of Allocation objects.
  2461. */
  2462. class AllocationObjectAllocator
  2463. {
  2464. D3D12MA_CLASS_NO_COPY(AllocationObjectAllocator);
  2465. public:
  2466. AllocationObjectAllocator(const ALLOCATION_CALLBACKS& allocationCallbacks)
  2467. : m_Allocator(allocationCallbacks, 1024) {}
  2468. template<typename... Types>
  2469. Allocation* Allocate(Types... args);
  2470. void Free(Allocation* alloc);
  2471. private:
  2472. D3D12MA_MUTEX m_Mutex;
  2473. PoolAllocator<Allocation> m_Allocator;
  2474. };
  2475. #ifndef _D3D12MA_ALLOCATION_OBJECT_ALLOCATOR_FUNCTIONS
  2476. template<typename... Types>
  2477. Allocation* AllocationObjectAllocator::Allocate(Types... args)
  2478. {
  2479. MutexLock mutexLock(m_Mutex);
  2480. return m_Allocator.Alloc(std::forward<Types>(args)...);
  2481. }
  2482. void AllocationObjectAllocator::Free(Allocation* alloc)
  2483. {
  2484. MutexLock mutexLock(m_Mutex);
  2485. m_Allocator.Free(alloc);
  2486. }
  2487. #endif // _D3D12MA_ALLOCATION_OBJECT_ALLOCATOR_FUNCTIONS
  2488. #endif // _D3D12MA_ALLOCATION_OBJECT_ALLOCATOR
  2489. #ifndef _D3D12MA_SUBALLOCATION
  2490. /*
  2491. Represents a region of NormalBlock that is either assigned and returned as
  2492. allocated memory block or free.
  2493. */
  2494. struct Suballocation
  2495. {
  2496. UINT64 offset;
  2497. UINT64 size;
  2498. void* privateData;
  2499. SuballocationType type;
  2500. };
  2501. using SuballocationList = List<Suballocation>;
  2502. // Comparator for offsets.
  2503. struct SuballocationOffsetLess
  2504. {
  2505. bool operator()(const Suballocation& lhs, const Suballocation& rhs) const
  2506. {
  2507. return lhs.offset < rhs.offset;
  2508. }
  2509. };
  2510. struct SuballocationOffsetGreater
  2511. {
  2512. bool operator()(const Suballocation& lhs, const Suballocation& rhs) const
  2513. {
  2514. return lhs.offset > rhs.offset;
  2515. }
  2516. };
  2517. struct SuballocationItemSizeLess
  2518. {
  2519. bool operator()(const SuballocationList::iterator lhs, const SuballocationList::iterator rhs) const
  2520. {
  2521. return lhs->size < rhs->size;
  2522. }
  2523. bool operator()(const SuballocationList::iterator lhs, UINT64 rhsSize) const
  2524. {
  2525. return lhs->size < rhsSize;
  2526. }
  2527. };
  2528. #endif // _D3D12MA_SUBALLOCATION
  2529. #ifndef _D3D12MA_ALLOCATION_REQUEST
  2530. /*
  2531. Parameters of planned allocation inside a NormalBlock.
  2532. */
  2533. struct AllocationRequest
  2534. {
  2535. AllocHandle allocHandle;
  2536. UINT64 size;
  2537. UINT64 algorithmData;
  2538. UINT64 sumFreeSize; // Sum size of free items that overlap with proposed allocation.
  2539. UINT64 sumItemSize; // Sum size of items to make lost that overlap with proposed allocation.
  2540. SuballocationList::iterator item;
  2541. BOOL zeroInitialized = FALSE; // TODO Implement proper handling in TLSF and Linear, using ZeroInitializedRange class.
  2542. };
  2543. #endif // _D3D12MA_ALLOCATION_REQUEST
  2544. #ifndef _D3D12MA_ZERO_INITIALIZED_RANGE
  2545. /*
  2546. Keeps track of the range of bytes that are surely initialized with zeros.
  2547. Everything outside of it is considered uninitialized memory that may contain
  2548. garbage data.
  2549. The range is left-inclusive.
  2550. */
  2551. class ZeroInitializedRange
  2552. {
  2553. public:
  2554. void Reset(UINT64 size);
  2555. BOOL IsRangeZeroInitialized(UINT64 beg, UINT64 end) const;
  2556. void MarkRangeAsUsed(UINT64 usedBeg, UINT64 usedEnd);
  2557. private:
  2558. UINT64 m_ZeroBeg = 0, m_ZeroEnd = 0;
  2559. };
  2560. #ifndef _D3D12MA_ZERO_INITIALIZED_RANGE_FUNCTIONS
  2561. void ZeroInitializedRange::Reset(UINT64 size)
  2562. {
  2563. D3D12MA_ASSERT(size > 0);
  2564. m_ZeroBeg = 0;
  2565. m_ZeroEnd = size;
  2566. }
  2567. BOOL ZeroInitializedRange::IsRangeZeroInitialized(UINT64 beg, UINT64 end) const
  2568. {
  2569. D3D12MA_ASSERT(beg < end);
  2570. return m_ZeroBeg <= beg && end <= m_ZeroEnd;
  2571. }
  2572. void ZeroInitializedRange::MarkRangeAsUsed(UINT64 usedBeg, UINT64 usedEnd)
  2573. {
  2574. D3D12MA_ASSERT(usedBeg < usedEnd);
  2575. // No new bytes marked.
  2576. if (usedEnd <= m_ZeroBeg || m_ZeroEnd <= usedBeg)
  2577. {
  2578. return;
  2579. }
  2580. // All bytes marked.
  2581. if (usedBeg <= m_ZeroBeg && m_ZeroEnd <= usedEnd)
  2582. {
  2583. m_ZeroBeg = m_ZeroEnd = 0;
  2584. }
  2585. // Some bytes marked.
  2586. else
  2587. {
  2588. const UINT64 remainingZeroBefore = usedBeg > m_ZeroBeg ? usedBeg - m_ZeroBeg : 0;
  2589. const UINT64 remainingZeroAfter = usedEnd < m_ZeroEnd ? m_ZeroEnd - usedEnd : 0;
  2590. D3D12MA_ASSERT(remainingZeroBefore > 0 || remainingZeroAfter > 0);
  2591. if (remainingZeroBefore > remainingZeroAfter)
  2592. {
  2593. m_ZeroEnd = usedBeg;
  2594. }
  2595. else
  2596. {
  2597. m_ZeroBeg = usedEnd;
  2598. }
  2599. }
  2600. }
  2601. #endif // _D3D12MA_ZERO_INITIALIZED_RANGE_FUNCTIONS
  2602. #endif // _D3D12MA_ZERO_INITIALIZED_RANGE
  2603. #ifndef _D3D12MA_BLOCK_METADATA
  2604. /*
  2605. Data structure used for bookkeeping of allocations and unused ranges of memory
  2606. in a single ID3D12Heap memory block.
  2607. */
  2608. class BlockMetadata
  2609. {
  2610. public:
  2611. BlockMetadata(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual);
  2612. virtual ~BlockMetadata() = default;
  2613. virtual void Init(UINT64 size) { m_Size = size; }
  2614. // Validates all data structures inside this object. If not valid, returns false.
  2615. virtual bool Validate() const = 0;
  2616. UINT64 GetSize() const { return m_Size; }
  2617. bool IsVirtual() const { return m_IsVirtual; }
  2618. virtual size_t GetAllocationCount() const = 0;
  2619. virtual size_t GetFreeRegionsCount() const = 0;
  2620. virtual UINT64 GetSumFreeSize() const = 0;
  2621. virtual UINT64 GetAllocationOffset(AllocHandle allocHandle) const = 0;
  2622. // Returns true if this block is empty - contains only single free suballocation.
  2623. virtual bool IsEmpty() const = 0;
  2624. virtual void GetAllocationInfo(AllocHandle allocHandle, VIRTUAL_ALLOCATION_INFO& outInfo) const = 0;
  2625. // Tries to find a place for suballocation with given parameters inside this block.
  2626. // If succeeded, fills pAllocationRequest and returns true.
  2627. // If failed, returns false.
  2628. virtual bool CreateAllocationRequest(
  2629. UINT64 allocSize,
  2630. UINT64 allocAlignment,
  2631. bool upperAddress,
  2632. UINT32 strategy,
  2633. AllocationRequest* pAllocationRequest) = 0;
  2634. // Makes actual allocation based on request. Request must already be checked and valid.
  2635. virtual void Alloc(
  2636. const AllocationRequest& request,
  2637. UINT64 allocSize,
  2638. void* PrivateData) = 0;
  2639. virtual void Free(AllocHandle allocHandle) = 0;
  2640. // Frees all allocations.
  2641. // Careful! Don't call it if there are Allocation objects owned by pPrivateData of of cleared allocations!
  2642. virtual void Clear() = 0;
  2643. virtual AllocHandle GetAllocationListBegin() const = 0;
  2644. virtual AllocHandle GetNextAllocation(AllocHandle prevAlloc) const = 0;
  2645. virtual UINT64 GetNextFreeRegionSize(AllocHandle alloc) const = 0;
  2646. virtual void* GetAllocationPrivateData(AllocHandle allocHandle) const = 0;
  2647. virtual void SetAllocationPrivateData(AllocHandle allocHandle, void* privateData) = 0;
  2648. virtual void AddStatistics(Statistics& inoutStats) const = 0;
  2649. virtual void AddDetailedStatistics(DetailedStatistics& inoutStats) const = 0;
  2650. virtual void WriteAllocationInfoToJson(JsonWriter& json) const = 0;
  2651. virtual void DebugLogAllAllocations() const = 0;
  2652. protected:
  2653. const ALLOCATION_CALLBACKS* GetAllocs() const { return m_pAllocationCallbacks; }
  2654. UINT64 GetDebugMargin() const { return IsVirtual() ? 0 : D3D12MA_DEBUG_MARGIN; }
  2655. void DebugLogAllocation(UINT64 offset, UINT64 size, void* privateData) const;
  2656. void PrintDetailedMap_Begin(JsonWriter& json,
  2657. UINT64 unusedBytes,
  2658. size_t allocationCount,
  2659. size_t unusedRangeCount) const;
  2660. void PrintDetailedMap_Allocation(JsonWriter& json,
  2661. UINT64 offset, UINT64 size, void* privateData) const;
  2662. void PrintDetailedMap_UnusedRange(JsonWriter& json,
  2663. UINT64 offset, UINT64 size) const;
  2664. void PrintDetailedMap_End(JsonWriter& json) const;
  2665. private:
  2666. UINT64 m_Size;
  2667. bool m_IsVirtual;
  2668. const ALLOCATION_CALLBACKS* m_pAllocationCallbacks;
  2669. D3D12MA_CLASS_NO_COPY(BlockMetadata);
  2670. };
  2671. #ifndef _D3D12MA_BLOCK_METADATA_FUNCTIONS
  2672. BlockMetadata::BlockMetadata(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual)
  2673. : m_Size(0),
  2674. m_IsVirtual(isVirtual),
  2675. m_pAllocationCallbacks(allocationCallbacks)
  2676. {
  2677. D3D12MA_ASSERT(allocationCallbacks);
  2678. }
  2679. void BlockMetadata::DebugLogAllocation(UINT64 offset, UINT64 size, void* privateData) const
  2680. {
  2681. if (IsVirtual())
  2682. {
  2683. D3D12MA_DEBUG_LOG(L"UNFREED VIRTUAL ALLOCATION; Offset: %llu; Size: %llu; PrivateData: %p", offset, size, privateData);
  2684. }
  2685. else
  2686. {
  2687. D3D12MA_ASSERT(privateData != NULL);
  2688. Allocation* allocation = reinterpret_cast<Allocation*>(privateData);
  2689. privateData = allocation->GetPrivateData();
  2690. LPCWSTR name = allocation->GetName();
  2691. D3D12MA_DEBUG_LOG(L"UNFREED ALLOCATION; Offset: %llu; Size: %llu; PrivateData: %p; Name: %s",
  2692. offset, size, privateData, name ? name : L"D3D12MA_Empty");
  2693. }
  2694. }
  2695. void BlockMetadata::PrintDetailedMap_Begin(JsonWriter& json,
  2696. UINT64 unusedBytes, size_t allocationCount, size_t unusedRangeCount) const
  2697. {
  2698. json.WriteString(L"TotalBytes");
  2699. json.WriteNumber(GetSize());
  2700. json.WriteString(L"UnusedBytes");
  2701. json.WriteNumber(unusedBytes);
  2702. json.WriteString(L"Allocations");
  2703. json.WriteNumber((UINT64)allocationCount);
  2704. json.WriteString(L"UnusedRanges");
  2705. json.WriteNumber((UINT64)unusedRangeCount);
  2706. json.WriteString(L"Suballocations");
  2707. json.BeginArray();
  2708. }
  2709. void BlockMetadata::PrintDetailedMap_Allocation(JsonWriter& json,
  2710. UINT64 offset, UINT64 size, void* privateData) const
  2711. {
  2712. json.BeginObject(true);
  2713. json.WriteString(L"Offset");
  2714. json.WriteNumber(offset);
  2715. if (IsVirtual())
  2716. {
  2717. json.WriteString(L"Size");
  2718. json.WriteNumber(size);
  2719. if (privateData)
  2720. {
  2721. json.WriteString(L"CustomData");
  2722. json.WriteNumber((uintptr_t)privateData);
  2723. }
  2724. }
  2725. else
  2726. {
  2727. const Allocation* const alloc = (const Allocation*)privateData;
  2728. D3D12MA_ASSERT(alloc);
  2729. json.AddAllocationToObject(*alloc);
  2730. }
  2731. json.EndObject();
  2732. }
  2733. void BlockMetadata::PrintDetailedMap_UnusedRange(JsonWriter& json,
  2734. UINT64 offset, UINT64 size) const
  2735. {
  2736. json.BeginObject(true);
  2737. json.WriteString(L"Offset");
  2738. json.WriteNumber(offset);
  2739. json.WriteString(L"Type");
  2740. json.WriteString(L"FREE");
  2741. json.WriteString(L"Size");
  2742. json.WriteNumber(size);
  2743. json.EndObject();
  2744. }
  2745. void BlockMetadata::PrintDetailedMap_End(JsonWriter& json) const
  2746. {
  2747. json.EndArray();
  2748. }
  2749. #endif // _D3D12MA_BLOCK_METADATA_FUNCTIONS
  2750. #endif // _D3D12MA_BLOCK_METADATA
  2751. #if 0
  2752. #ifndef _D3D12MA_BLOCK_METADATA_GENERIC
  2753. class BlockMetadata_Generic : public BlockMetadata
  2754. {
  2755. public:
  2756. BlockMetadata_Generic(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual);
  2757. virtual ~BlockMetadata_Generic() = default;
  2758. size_t GetAllocationCount() const override { return m_Suballocations.size() - m_FreeCount; }
  2759. UINT64 GetSumFreeSize() const override { return m_SumFreeSize; }
  2760. UINT64 GetAllocationOffset(AllocHandle allocHandle) const override { return (UINT64)allocHandle - 1; }
  2761. void Init(UINT64 size) override;
  2762. bool Validate() const override;
  2763. bool IsEmpty() const override;
  2764. void GetAllocationInfo(AllocHandle allocHandle, VIRTUAL_ALLOCATION_INFO& outInfo) const override;
  2765. bool CreateAllocationRequest(
  2766. UINT64 allocSize,
  2767. UINT64 allocAlignment,
  2768. bool upperAddress,
  2769. AllocationRequest* pAllocationRequest) override;
  2770. void Alloc(
  2771. const AllocationRequest& request,
  2772. UINT64 allocSize,
  2773. void* privateData) override;
  2774. void Free(AllocHandle allocHandle) override;
  2775. void Clear() override;
  2776. void SetAllocationPrivateData(AllocHandle allocHandle, void* privateData) override;
  2777. void AddStatistics(Statistics& inoutStats) const override;
  2778. void AddDetailedStatistics(DetailedStatistics& inoutStats) const override;
  2779. void WriteAllocationInfoToJson(JsonWriter& json) const override;
  2780. private:
  2781. UINT m_FreeCount;
  2782. UINT64 m_SumFreeSize;
  2783. SuballocationList m_Suballocations;
  2784. // Suballocations that are free and have size greater than certain threshold.
  2785. // Sorted by size, ascending.
  2786. Vector<SuballocationList::iterator> m_FreeSuballocationsBySize;
  2787. ZeroInitializedRange m_ZeroInitializedRange;
  2788. SuballocationList::const_iterator FindAtOffset(UINT64 offset) const;
  2789. bool ValidateFreeSuballocationList() const;
  2790. // Checks if requested suballocation with given parameters can be placed in given pFreeSuballocItem.
  2791. // If yes, fills pOffset and returns true. If no, returns false.
  2792. bool CheckAllocation(
  2793. UINT64 allocSize,
  2794. UINT64 allocAlignment,
  2795. SuballocationList::const_iterator suballocItem,
  2796. AllocHandle* pAllocHandle,
  2797. UINT64* pSumFreeSize,
  2798. UINT64* pSumItemSize,
  2799. BOOL *pZeroInitialized) const;
  2800. // Given free suballocation, it merges it with following one, which must also be free.
  2801. void MergeFreeWithNext(SuballocationList::iterator item);
  2802. // Releases given suballocation, making it free.
  2803. // Merges it with adjacent free suballocations if applicable.
  2804. // Returns iterator to new free suballocation at this place.
  2805. SuballocationList::iterator FreeSuballocation(SuballocationList::iterator suballocItem);
  2806. // Given free suballocation, it inserts it into sorted list of
  2807. // m_FreeSuballocationsBySize if it's suitable.
  2808. void RegisterFreeSuballocation(SuballocationList::iterator item);
  2809. // Given free suballocation, it removes it from sorted list of
  2810. // m_FreeSuballocationsBySize if it's suitable.
  2811. void UnregisterFreeSuballocation(SuballocationList::iterator item);
  2812. D3D12MA_CLASS_NO_COPY(BlockMetadata_Generic)
  2813. };
  2814. #ifndef _D3D12MA_BLOCK_METADATA_GENERIC_FUNCTIONS
  2815. BlockMetadata_Generic::BlockMetadata_Generic(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual)
  2816. : BlockMetadata(allocationCallbacks, isVirtual),
  2817. m_FreeCount(0),
  2818. m_SumFreeSize(0),
  2819. m_Suballocations(*allocationCallbacks),
  2820. m_FreeSuballocationsBySize(*allocationCallbacks)
  2821. {
  2822. D3D12MA_ASSERT(allocationCallbacks);
  2823. }
  2824. void BlockMetadata_Generic::Init(UINT64 size)
  2825. {
  2826. BlockMetadata::Init(size);
  2827. m_ZeroInitializedRange.Reset(size);
  2828. m_FreeCount = 1;
  2829. m_SumFreeSize = size;
  2830. Suballocation suballoc = {};
  2831. suballoc.offset = 0;
  2832. suballoc.size = size;
  2833. suballoc.type = SUBALLOCATION_TYPE_FREE;
  2834. suballoc.privateData = NULL;
  2835. D3D12MA_ASSERT(size > MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER);
  2836. m_Suballocations.push_back(suballoc);
  2837. SuballocationList::iterator suballocItem = m_Suballocations.end();
  2838. --suballocItem;
  2839. m_FreeSuballocationsBySize.push_back(suballocItem);
  2840. }
  2841. bool BlockMetadata_Generic::Validate() const
  2842. {
  2843. D3D12MA_VALIDATE(!m_Suballocations.empty());
  2844. // Expected offset of new suballocation as calculated from previous ones.
  2845. UINT64 calculatedOffset = 0;
  2846. // Expected number of free suballocations as calculated from traversing their list.
  2847. UINT calculatedFreeCount = 0;
  2848. // Expected sum size of free suballocations as calculated from traversing their list.
  2849. UINT64 calculatedSumFreeSize = 0;
  2850. // Expected number of free suballocations that should be registered in
  2851. // m_FreeSuballocationsBySize calculated from traversing their list.
  2852. size_t freeSuballocationsToRegister = 0;
  2853. // True if previous visited suballocation was free.
  2854. bool prevFree = false;
  2855. for (const auto& subAlloc : m_Suballocations)
  2856. {
  2857. // Actual offset of this suballocation doesn't match expected one.
  2858. D3D12MA_VALIDATE(subAlloc.offset == calculatedOffset);
  2859. const bool currFree = (subAlloc.type == SUBALLOCATION_TYPE_FREE);
  2860. // Two adjacent free suballocations are invalid. They should be merged.
  2861. D3D12MA_VALIDATE(!prevFree || !currFree);
  2862. const Allocation* const alloc = (Allocation*)subAlloc.privateData;
  2863. if (!IsVirtual())
  2864. {
  2865. D3D12MA_VALIDATE(currFree == (alloc == NULL));
  2866. }
  2867. if (currFree)
  2868. {
  2869. calculatedSumFreeSize += subAlloc.size;
  2870. ++calculatedFreeCount;
  2871. if (subAlloc.size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
  2872. {
  2873. ++freeSuballocationsToRegister;
  2874. }
  2875. // Margin required between allocations - every free space must be at least that large.
  2876. D3D12MA_VALIDATE(subAlloc.size >= GetDebugMargin());
  2877. }
  2878. else
  2879. {
  2880. if (!IsVirtual())
  2881. {
  2882. D3D12MA_VALIDATE(alloc->GetOffset() == subAlloc.offset);
  2883. D3D12MA_VALIDATE(alloc->GetSize() == subAlloc.size);
  2884. }
  2885. // Margin required between allocations - previous allocation must be free.
  2886. D3D12MA_VALIDATE(GetDebugMargin() == 0 || prevFree);
  2887. }
  2888. calculatedOffset += subAlloc.size;
  2889. prevFree = currFree;
  2890. }
  2891. // Number of free suballocations registered in m_FreeSuballocationsBySize doesn't
  2892. // match expected one.
  2893. D3D12MA_VALIDATE(m_FreeSuballocationsBySize.size() == freeSuballocationsToRegister);
  2894. UINT64 lastSize = 0;
  2895. for (size_t i = 0; i < m_FreeSuballocationsBySize.size(); ++i)
  2896. {
  2897. SuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[i];
  2898. // Only free suballocations can be registered in m_FreeSuballocationsBySize.
  2899. D3D12MA_VALIDATE(suballocItem->type == SUBALLOCATION_TYPE_FREE);
  2900. // They must be sorted by size ascending.
  2901. D3D12MA_VALIDATE(suballocItem->size >= lastSize);
  2902. lastSize = suballocItem->size;
  2903. }
  2904. // Check if totals match calculacted values.
  2905. D3D12MA_VALIDATE(ValidateFreeSuballocationList());
  2906. D3D12MA_VALIDATE(calculatedOffset == GetSize());
  2907. D3D12MA_VALIDATE(calculatedSumFreeSize == m_SumFreeSize);
  2908. D3D12MA_VALIDATE(calculatedFreeCount == m_FreeCount);
  2909. return true;
  2910. }
  2911. bool BlockMetadata_Generic::IsEmpty() const
  2912. {
  2913. return (m_Suballocations.size() == 1) && (m_FreeCount == 1);
  2914. }
  2915. void BlockMetadata_Generic::GetAllocationInfo(AllocHandle allocHandle, VIRTUAL_ALLOCATION_INFO& outInfo) const
  2916. {
  2917. Suballocation& suballoc = *FindAtOffset((UINT64)allocHandle - 1).dropConst();
  2918. outInfo.Offset = suballoc.offset;
  2919. outInfo.Size = suballoc.size;
  2920. outInfo.pPrivateData = suballoc.privateData;
  2921. }
  2922. bool BlockMetadata_Generic::CreateAllocationRequest(
  2923. UINT64 allocSize,
  2924. UINT64 allocAlignment,
  2925. bool upperAddress,
  2926. AllocationRequest* pAllocationRequest)
  2927. {
  2928. D3D12MA_ASSERT(allocSize > 0);
  2929. D3D12MA_ASSERT(!upperAddress && "ALLOCATION_FLAG_UPPER_ADDRESS can be used only with linear algorithm.");
  2930. D3D12MA_ASSERT(pAllocationRequest != NULL);
  2931. D3D12MA_HEAVY_ASSERT(Validate());
  2932. // There is not enough total free space in this block to fullfill the request: Early return.
  2933. if (m_SumFreeSize < allocSize + GetDebugMargin())
  2934. {
  2935. return false;
  2936. }
  2937. // New algorithm, efficiently searching freeSuballocationsBySize.
  2938. const size_t freeSuballocCount = m_FreeSuballocationsBySize.size();
  2939. if (freeSuballocCount > 0)
  2940. {
  2941. // Find first free suballocation with size not less than allocSize + GetDebugMargin().
  2942. SuballocationList::iterator* const it = BinaryFindFirstNotLess(
  2943. m_FreeSuballocationsBySize.data(),
  2944. m_FreeSuballocationsBySize.data() + freeSuballocCount,
  2945. allocSize + GetDebugMargin(),
  2946. SuballocationItemSizeLess());
  2947. size_t index = it - m_FreeSuballocationsBySize.data();
  2948. for (; index < freeSuballocCount; ++index)
  2949. {
  2950. if (CheckAllocation(
  2951. allocSize,
  2952. allocAlignment,
  2953. m_FreeSuballocationsBySize[index],
  2954. &pAllocationRequest->allocHandle,
  2955. &pAllocationRequest->sumFreeSize,
  2956. &pAllocationRequest->sumItemSize,
  2957. &pAllocationRequest->zeroInitialized))
  2958. {
  2959. pAllocationRequest->item = m_FreeSuballocationsBySize[index];
  2960. return true;
  2961. }
  2962. }
  2963. }
  2964. return false;
  2965. }
  2966. void BlockMetadata_Generic::Alloc(
  2967. const AllocationRequest& request,
  2968. UINT64 allocSize,
  2969. void* privateData)
  2970. {
  2971. D3D12MA_ASSERT(request.item != m_Suballocations.end());
  2972. Suballocation& suballoc = *request.item;
  2973. // Given suballocation is a free block.
  2974. D3D12MA_ASSERT(suballoc.type == SUBALLOCATION_TYPE_FREE);
  2975. // Given offset is inside this suballocation.
  2976. UINT64 offset = (UINT64)request.allocHandle - 1;
  2977. D3D12MA_ASSERT(offset >= suballoc.offset);
  2978. const UINT64 paddingBegin = offset - suballoc.offset;
  2979. D3D12MA_ASSERT(suballoc.size >= paddingBegin + allocSize);
  2980. const UINT64 paddingEnd = suballoc.size - paddingBegin - allocSize;
  2981. // Unregister this free suballocation from m_FreeSuballocationsBySize and update
  2982. // it to become used.
  2983. UnregisterFreeSuballocation(request.item);
  2984. suballoc.offset = offset;
  2985. suballoc.size = allocSize;
  2986. suballoc.type = SUBALLOCATION_TYPE_ALLOCATION;
  2987. suballoc.privateData = privateData;
  2988. // If there are any free bytes remaining at the end, insert new free suballocation after current one.
  2989. if (paddingEnd)
  2990. {
  2991. Suballocation paddingSuballoc = {};
  2992. paddingSuballoc.offset = offset + allocSize;
  2993. paddingSuballoc.size = paddingEnd;
  2994. paddingSuballoc.type = SUBALLOCATION_TYPE_FREE;
  2995. SuballocationList::iterator next = request.item;
  2996. ++next;
  2997. const SuballocationList::iterator paddingEndItem =
  2998. m_Suballocations.insert(next, paddingSuballoc);
  2999. RegisterFreeSuballocation(paddingEndItem);
  3000. }
  3001. // If there are any free bytes remaining at the beginning, insert new free suballocation before current one.
  3002. if (paddingBegin)
  3003. {
  3004. Suballocation paddingSuballoc = {};
  3005. paddingSuballoc.offset = offset - paddingBegin;
  3006. paddingSuballoc.size = paddingBegin;
  3007. paddingSuballoc.type = SUBALLOCATION_TYPE_FREE;
  3008. const SuballocationList::iterator paddingBeginItem =
  3009. m_Suballocations.insert(request.item, paddingSuballoc);
  3010. RegisterFreeSuballocation(paddingBeginItem);
  3011. }
  3012. // Update totals.
  3013. m_FreeCount = m_FreeCount - 1;
  3014. if (paddingBegin > 0)
  3015. {
  3016. ++m_FreeCount;
  3017. }
  3018. if (paddingEnd > 0)
  3019. {
  3020. ++m_FreeCount;
  3021. }
  3022. m_SumFreeSize -= allocSize;
  3023. m_ZeroInitializedRange.MarkRangeAsUsed(offset, offset + allocSize);
  3024. }
  3025. void BlockMetadata_Generic::Free(AllocHandle allocHandle)
  3026. {
  3027. FreeSuballocation(FindAtOffset((UINT64)allocHandle - 1).dropConst());
  3028. }
  3029. void BlockMetadata_Generic::Clear()
  3030. {
  3031. m_FreeCount = 1;
  3032. m_SumFreeSize = GetSize();
  3033. m_Suballocations.clear();
  3034. Suballocation suballoc = {};
  3035. suballoc.offset = 0;
  3036. suballoc.size = GetSize();
  3037. suballoc.type = SUBALLOCATION_TYPE_FREE;
  3038. m_Suballocations.push_back(suballoc);
  3039. m_FreeSuballocationsBySize.clear();
  3040. m_FreeSuballocationsBySize.push_back(m_Suballocations.begin());
  3041. }
  3042. SuballocationList::const_iterator BlockMetadata_Generic::FindAtOffset(UINT64 offset) const
  3043. {
  3044. const UINT64 last = m_Suballocations.crbegin()->offset;
  3045. if (last == offset)
  3046. return m_Suballocations.crbegin();
  3047. const UINT64 first = m_Suballocations.cbegin()->offset;
  3048. if (first == offset)
  3049. return m_Suballocations.cbegin();
  3050. const size_t suballocCount = m_Suballocations.size();
  3051. const UINT64 step = (last - first + m_Suballocations.cbegin()->size) / suballocCount;
  3052. auto findSuballocation = [&](auto begin, auto end) -> SuballocationList::const_iterator
  3053. {
  3054. for (auto suballocItem = begin;
  3055. suballocItem != end;
  3056. ++suballocItem)
  3057. {
  3058. const Suballocation& suballoc = *suballocItem;
  3059. if (suballoc.offset == offset)
  3060. return suballocItem;
  3061. }
  3062. D3D12MA_ASSERT(false && "Not found!");
  3063. return m_Suballocations.end();
  3064. };
  3065. // If requested offset is closer to the end of range, search from the end
  3066. if ((offset - first) > suballocCount * step / 2)
  3067. {
  3068. return findSuballocation(m_Suballocations.crbegin(), m_Suballocations.crend());
  3069. }
  3070. return findSuballocation(m_Suballocations.cbegin(), m_Suballocations.cend());
  3071. }
  3072. bool BlockMetadata_Generic::ValidateFreeSuballocationList() const
  3073. {
  3074. UINT64 lastSize = 0;
  3075. for (size_t i = 0, count = m_FreeSuballocationsBySize.size(); i < count; ++i)
  3076. {
  3077. const SuballocationList::iterator it = m_FreeSuballocationsBySize[i];
  3078. D3D12MA_VALIDATE(it->type == SUBALLOCATION_TYPE_FREE);
  3079. D3D12MA_VALIDATE(it->size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER);
  3080. D3D12MA_VALIDATE(it->size >= lastSize);
  3081. lastSize = it->size;
  3082. }
  3083. return true;
  3084. }
  3085. bool BlockMetadata_Generic::CheckAllocation(
  3086. UINT64 allocSize,
  3087. UINT64 allocAlignment,
  3088. SuballocationList::const_iterator suballocItem,
  3089. AllocHandle* pAllocHandle,
  3090. UINT64* pSumFreeSize,
  3091. UINT64* pSumItemSize,
  3092. BOOL* pZeroInitialized) const
  3093. {
  3094. D3D12MA_ASSERT(allocSize > 0);
  3095. D3D12MA_ASSERT(suballocItem != m_Suballocations.cend());
  3096. D3D12MA_ASSERT(pAllocHandle != NULL && pZeroInitialized != NULL);
  3097. *pSumFreeSize = 0;
  3098. *pSumItemSize = 0;
  3099. *pZeroInitialized = FALSE;
  3100. const Suballocation& suballoc = *suballocItem;
  3101. D3D12MA_ASSERT(suballoc.type == SUBALLOCATION_TYPE_FREE);
  3102. *pSumFreeSize = suballoc.size;
  3103. // Size of this suballocation is too small for this request: Early return.
  3104. if (suballoc.size < allocSize)
  3105. {
  3106. return false;
  3107. }
  3108. // Start from offset equal to beginning of this suballocation and debug margin of previous allocation if present.
  3109. UINT64 offset = suballoc.offset + (suballocItem == m_Suballocations.cbegin() ? 0 : GetDebugMargin());
  3110. // Apply alignment.
  3111. offset = AlignUp(offset, allocAlignment);
  3112. // Calculate padding at the beginning based on current offset.
  3113. const UINT64 paddingBegin = offset - suballoc.offset;
  3114. // Fail if requested size plus margin after is bigger than size of this suballocation.
  3115. if (paddingBegin + allocSize + GetDebugMargin() > suballoc.size)
  3116. {
  3117. return false;
  3118. }
  3119. // All tests passed: Success. Offset is already filled.
  3120. *pZeroInitialized = m_ZeroInitializedRange.IsRangeZeroInitialized(offset, offset + allocSize);
  3121. *pAllocHandle = (AllocHandle)(offset + 1);
  3122. return true;
  3123. }
  3124. void BlockMetadata_Generic::MergeFreeWithNext(SuballocationList::iterator item)
  3125. {
  3126. D3D12MA_ASSERT(item != m_Suballocations.end());
  3127. D3D12MA_ASSERT(item->type == SUBALLOCATION_TYPE_FREE);
  3128. SuballocationList::iterator nextItem = item;
  3129. ++nextItem;
  3130. D3D12MA_ASSERT(nextItem != m_Suballocations.end());
  3131. D3D12MA_ASSERT(nextItem->type == SUBALLOCATION_TYPE_FREE);
  3132. item->size += nextItem->size;
  3133. --m_FreeCount;
  3134. m_Suballocations.erase(nextItem);
  3135. }
  3136. SuballocationList::iterator BlockMetadata_Generic::FreeSuballocation(SuballocationList::iterator suballocItem)
  3137. {
  3138. // Change this suballocation to be marked as free.
  3139. Suballocation& suballoc = *suballocItem;
  3140. suballoc.type = SUBALLOCATION_TYPE_FREE;
  3141. suballoc.privateData = NULL;
  3142. // Update totals.
  3143. ++m_FreeCount;
  3144. m_SumFreeSize += suballoc.size;
  3145. // Merge with previous and/or next suballocation if it's also free.
  3146. bool mergeWithNext = false;
  3147. bool mergeWithPrev = false;
  3148. SuballocationList::iterator nextItem = suballocItem;
  3149. ++nextItem;
  3150. if ((nextItem != m_Suballocations.end()) && (nextItem->type == SUBALLOCATION_TYPE_FREE))
  3151. {
  3152. mergeWithNext = true;
  3153. }
  3154. SuballocationList::iterator prevItem = suballocItem;
  3155. if (suballocItem != m_Suballocations.begin())
  3156. {
  3157. --prevItem;
  3158. if (prevItem->type == SUBALLOCATION_TYPE_FREE)
  3159. {
  3160. mergeWithPrev = true;
  3161. }
  3162. }
  3163. if (mergeWithNext)
  3164. {
  3165. UnregisterFreeSuballocation(nextItem);
  3166. MergeFreeWithNext(suballocItem);
  3167. }
  3168. if (mergeWithPrev)
  3169. {
  3170. UnregisterFreeSuballocation(prevItem);
  3171. MergeFreeWithNext(prevItem);
  3172. RegisterFreeSuballocation(prevItem);
  3173. return prevItem;
  3174. }
  3175. else
  3176. {
  3177. RegisterFreeSuballocation(suballocItem);
  3178. return suballocItem;
  3179. }
  3180. }
  3181. void BlockMetadata_Generic::RegisterFreeSuballocation(SuballocationList::iterator item)
  3182. {
  3183. D3D12MA_ASSERT(item->type == SUBALLOCATION_TYPE_FREE);
  3184. D3D12MA_ASSERT(item->size > 0);
  3185. // You may want to enable this validation at the beginning or at the end of
  3186. // this function, depending on what do you want to check.
  3187. D3D12MA_HEAVY_ASSERT(ValidateFreeSuballocationList());
  3188. if (item->size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
  3189. {
  3190. if (m_FreeSuballocationsBySize.empty())
  3191. {
  3192. m_FreeSuballocationsBySize.push_back(item);
  3193. }
  3194. else
  3195. {
  3196. m_FreeSuballocationsBySize.InsertSorted(item, SuballocationItemSizeLess());
  3197. }
  3198. }
  3199. //D3D12MA_HEAVY_ASSERT(ValidateFreeSuballocationList());
  3200. }
  3201. void BlockMetadata_Generic::UnregisterFreeSuballocation(SuballocationList::iterator item)
  3202. {
  3203. D3D12MA_ASSERT(item->type == SUBALLOCATION_TYPE_FREE);
  3204. D3D12MA_ASSERT(item->size > 0);
  3205. // You may want to enable this validation at the beginning or at the end of
  3206. // this function, depending on what do you want to check.
  3207. D3D12MA_HEAVY_ASSERT(ValidateFreeSuballocationList());
  3208. if (item->size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
  3209. {
  3210. SuballocationList::iterator* const it = BinaryFindFirstNotLess(
  3211. m_FreeSuballocationsBySize.data(),
  3212. m_FreeSuballocationsBySize.data() + m_FreeSuballocationsBySize.size(),
  3213. item,
  3214. SuballocationItemSizeLess());
  3215. for (size_t index = it - m_FreeSuballocationsBySize.data();
  3216. index < m_FreeSuballocationsBySize.size();
  3217. ++index)
  3218. {
  3219. if (m_FreeSuballocationsBySize[index] == item)
  3220. {
  3221. m_FreeSuballocationsBySize.remove(index);
  3222. return;
  3223. }
  3224. D3D12MA_ASSERT((m_FreeSuballocationsBySize[index]->size == item->size) && "Not found.");
  3225. }
  3226. D3D12MA_ASSERT(0 && "Not found.");
  3227. }
  3228. //D3D12MA_HEAVY_ASSERT(ValidateFreeSuballocationList());
  3229. }
  3230. void BlockMetadata_Generic::SetAllocationPrivateData(AllocHandle allocHandle, void* privateData)
  3231. {
  3232. Suballocation& suballoc = *FindAtOffset((UINT64)allocHandle - 1).dropConst();
  3233. suballoc.privateData = privateData;
  3234. }
  3235. void BlockMetadata_Generic::AddStatistics(Statistics& inoutStats) const
  3236. {
  3237. inoutStats.BlockCount++;
  3238. inoutStats.AllocationCount += (UINT)m_Suballocations.size() - m_FreeCount;
  3239. inoutStats.BlockBytes += GetSize();
  3240. inoutStats.AllocationBytes += GetSize() - m_SumFreeSize;
  3241. }
  3242. void BlockMetadata_Generic::AddDetailedStatistics(DetailedStatistics& inoutStats) const
  3243. {
  3244. inoutStats.Stats.BlockCount++;
  3245. inoutStats.Stats.BlockBytes += GetSize();
  3246. for (const auto& suballoc : m_Suballocations)
  3247. {
  3248. if (suballoc.type == SUBALLOCATION_TYPE_FREE)
  3249. AddDetailedStatisticsUnusedRange(inoutStats, suballoc.size);
  3250. else
  3251. AddDetailedStatisticsAllocation(inoutStats, suballoc.size);
  3252. }
  3253. }
  3254. void BlockMetadata_Generic::WriteAllocationInfoToJson(JsonWriter& json) const
  3255. {
  3256. PrintDetailedMap_Begin(json, GetSumFreeSize(), GetAllocationCount(), m_FreeCount);
  3257. for (const auto& suballoc : m_Suballocations)
  3258. {
  3259. if (suballoc.type == SUBALLOCATION_TYPE_FREE)
  3260. PrintDetailedMap_UnusedRange(json, suballoc.offset, suballoc.size);
  3261. else
  3262. PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.privateData);
  3263. }
  3264. PrintDetailedMap_End(json);
  3265. }
  3266. #endif // _D3D12MA_BLOCK_METADATA_GENERIC_FUNCTIONS
  3267. #endif // _D3D12MA_BLOCK_METADATA_GENERIC
  3268. #endif // #if 0
  3269. #ifndef _D3D12MA_BLOCK_METADATA_LINEAR
  3270. class BlockMetadata_Linear : public BlockMetadata
  3271. {
  3272. public:
  3273. BlockMetadata_Linear(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual);
  3274. virtual ~BlockMetadata_Linear() = default;
  3275. UINT64 GetSumFreeSize() const override { return m_SumFreeSize; }
  3276. bool IsEmpty() const override { return GetAllocationCount() == 0; }
  3277. UINT64 GetAllocationOffset(AllocHandle allocHandle) const override { return (UINT64)allocHandle - 1; };
  3278. void Init(UINT64 size) override;
  3279. bool Validate() const override;
  3280. size_t GetAllocationCount() const override;
  3281. size_t GetFreeRegionsCount() const override;
  3282. void GetAllocationInfo(AllocHandle allocHandle, VIRTUAL_ALLOCATION_INFO& outInfo) const override;
  3283. bool CreateAllocationRequest(
  3284. UINT64 allocSize,
  3285. UINT64 allocAlignment,
  3286. bool upperAddress,
  3287. UINT32 strategy,
  3288. AllocationRequest* pAllocationRequest) override;
  3289. void Alloc(
  3290. const AllocationRequest& request,
  3291. UINT64 allocSize,
  3292. void* privateData) override;
  3293. void Free(AllocHandle allocHandle) override;
  3294. void Clear() override;
  3295. AllocHandle GetAllocationListBegin() const override;
  3296. AllocHandle GetNextAllocation(AllocHandle prevAlloc) const override;
  3297. UINT64 GetNextFreeRegionSize(AllocHandle alloc) const override;
  3298. void* GetAllocationPrivateData(AllocHandle allocHandle) const override;
  3299. void SetAllocationPrivateData(AllocHandle allocHandle, void* privateData) override;
  3300. void AddStatistics(Statistics& inoutStats) const override;
  3301. void AddDetailedStatistics(DetailedStatistics& inoutStats) const override;
  3302. void WriteAllocationInfoToJson(JsonWriter& json) const override;
  3303. void DebugLogAllAllocations() const override;
  3304. private:
  3305. /*
  3306. There are two suballocation vectors, used in ping-pong way.
  3307. The one with index m_1stVectorIndex is called 1st.
  3308. The one with index (m_1stVectorIndex ^ 1) is called 2nd.
  3309. 2nd can be non-empty only when 1st is not empty.
  3310. When 2nd is not empty, m_2ndVectorMode indicates its mode of operation.
  3311. */
  3312. typedef Vector<Suballocation> SuballocationVectorType;
  3313. enum ALLOC_REQUEST_TYPE
  3314. {
  3315. ALLOC_REQUEST_UPPER_ADDRESS,
  3316. ALLOC_REQUEST_END_OF_1ST,
  3317. ALLOC_REQUEST_END_OF_2ND,
  3318. };
  3319. enum SECOND_VECTOR_MODE
  3320. {
  3321. SECOND_VECTOR_EMPTY,
  3322. /*
  3323. Suballocations in 2nd vector are created later than the ones in 1st, but they
  3324. all have smaller offset.
  3325. */
  3326. SECOND_VECTOR_RING_BUFFER,
  3327. /*
  3328. Suballocations in 2nd vector are upper side of double stack.
  3329. They all have offsets higher than those in 1st vector.
  3330. Top of this stack means smaller offsets, but higher indices in this vector.
  3331. */
  3332. SECOND_VECTOR_DOUBLE_STACK,
  3333. };
  3334. UINT64 m_SumFreeSize;
  3335. SuballocationVectorType m_Suballocations0, m_Suballocations1;
  3336. UINT32 m_1stVectorIndex;
  3337. SECOND_VECTOR_MODE m_2ndVectorMode;
  3338. // Number of items in 1st vector with hAllocation = null at the beginning.
  3339. size_t m_1stNullItemsBeginCount;
  3340. // Number of other items in 1st vector with hAllocation = null somewhere in the middle.
  3341. size_t m_1stNullItemsMiddleCount;
  3342. // Number of items in 2nd vector with hAllocation = null.
  3343. size_t m_2ndNullItemsCount;
  3344. SuballocationVectorType& AccessSuballocations1st() { return m_1stVectorIndex ? m_Suballocations1 : m_Suballocations0; }
  3345. SuballocationVectorType& AccessSuballocations2nd() { return m_1stVectorIndex ? m_Suballocations0 : m_Suballocations1; }
  3346. const SuballocationVectorType& AccessSuballocations1st() const { return m_1stVectorIndex ? m_Suballocations1 : m_Suballocations0; }
  3347. const SuballocationVectorType& AccessSuballocations2nd() const { return m_1stVectorIndex ? m_Suballocations0 : m_Suballocations1; }
  3348. Suballocation& FindSuballocation(UINT64 offset) const;
  3349. bool ShouldCompact1st() const;
  3350. void CleanupAfterFree();
  3351. bool CreateAllocationRequest_LowerAddress(
  3352. UINT64 allocSize,
  3353. UINT64 allocAlignment,
  3354. AllocationRequest* pAllocationRequest);
  3355. bool CreateAllocationRequest_UpperAddress(
  3356. UINT64 allocSize,
  3357. UINT64 allocAlignment,
  3358. AllocationRequest* pAllocationRequest);
  3359. D3D12MA_CLASS_NO_COPY(BlockMetadata_Linear)
  3360. };
  3361. #ifndef _D3D12MA_BLOCK_METADATA_LINEAR_FUNCTIONS
  3362. BlockMetadata_Linear::BlockMetadata_Linear(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual)
  3363. : BlockMetadata(allocationCallbacks, isVirtual),
  3364. m_SumFreeSize(0),
  3365. m_Suballocations0(*allocationCallbacks),
  3366. m_Suballocations1(*allocationCallbacks),
  3367. m_1stVectorIndex(0),
  3368. m_2ndVectorMode(SECOND_VECTOR_EMPTY),
  3369. m_1stNullItemsBeginCount(0),
  3370. m_1stNullItemsMiddleCount(0),
  3371. m_2ndNullItemsCount(0)
  3372. {
  3373. D3D12MA_ASSERT(allocationCallbacks);
  3374. }
  3375. void BlockMetadata_Linear::Init(UINT64 size)
  3376. {
  3377. BlockMetadata::Init(size);
  3378. m_SumFreeSize = size;
  3379. }
  3380. bool BlockMetadata_Linear::Validate() const
  3381. {
  3382. D3D12MA_VALIDATE(GetSumFreeSize() <= GetSize());
  3383. const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
  3384. const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
  3385. D3D12MA_VALIDATE(suballocations2nd.empty() == (m_2ndVectorMode == SECOND_VECTOR_EMPTY));
  3386. D3D12MA_VALIDATE(!suballocations1st.empty() ||
  3387. suballocations2nd.empty() ||
  3388. m_2ndVectorMode != SECOND_VECTOR_RING_BUFFER);
  3389. if (!suballocations1st.empty())
  3390. {
  3391. // Null item at the beginning should be accounted into m_1stNullItemsBeginCount.
  3392. D3D12MA_VALIDATE(suballocations1st[m_1stNullItemsBeginCount].type != SUBALLOCATION_TYPE_FREE);
  3393. // Null item at the end should be just pop_back().
  3394. D3D12MA_VALIDATE(suballocations1st.back().type != SUBALLOCATION_TYPE_FREE);
  3395. }
  3396. if (!suballocations2nd.empty())
  3397. {
  3398. // Null item at the end should be just pop_back().
  3399. D3D12MA_VALIDATE(suballocations2nd.back().type != SUBALLOCATION_TYPE_FREE);
  3400. }
  3401. D3D12MA_VALIDATE(m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount <= suballocations1st.size());
  3402. D3D12MA_VALIDATE(m_2ndNullItemsCount <= suballocations2nd.size());
  3403. UINT64 sumUsedSize = 0;
  3404. const size_t suballoc1stCount = suballocations1st.size();
  3405. UINT64 offset = 0;
  3406. if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
  3407. {
  3408. const size_t suballoc2ndCount = suballocations2nd.size();
  3409. size_t nullItem2ndCount = 0;
  3410. for (size_t i = 0; i < suballoc2ndCount; ++i)
  3411. {
  3412. const Suballocation& suballoc = suballocations2nd[i];
  3413. const bool currFree = (suballoc.type == SUBALLOCATION_TYPE_FREE);
  3414. const Allocation* alloc = (Allocation*)suballoc.privateData;
  3415. if (!IsVirtual())
  3416. {
  3417. D3D12MA_VALIDATE(currFree == (alloc == NULL));
  3418. }
  3419. D3D12MA_VALIDATE(suballoc.offset >= offset);
  3420. if (!currFree)
  3421. {
  3422. if (!IsVirtual())
  3423. {
  3424. D3D12MA_VALIDATE(GetAllocationOffset(alloc->GetAllocHandle()) == suballoc.offset);
  3425. D3D12MA_VALIDATE(alloc->GetSize() == suballoc.size);
  3426. }
  3427. sumUsedSize += suballoc.size;
  3428. }
  3429. else
  3430. {
  3431. ++nullItem2ndCount;
  3432. }
  3433. offset = suballoc.offset + suballoc.size + GetDebugMargin();
  3434. }
  3435. D3D12MA_VALIDATE(nullItem2ndCount == m_2ndNullItemsCount);
  3436. }
  3437. for (size_t i = 0; i < m_1stNullItemsBeginCount; ++i)
  3438. {
  3439. const Suballocation& suballoc = suballocations1st[i];
  3440. D3D12MA_VALIDATE(suballoc.type == SUBALLOCATION_TYPE_FREE &&
  3441. suballoc.privateData == NULL);
  3442. }
  3443. size_t nullItem1stCount = m_1stNullItemsBeginCount;
  3444. for (size_t i = m_1stNullItemsBeginCount; i < suballoc1stCount; ++i)
  3445. {
  3446. const Suballocation& suballoc = suballocations1st[i];
  3447. const bool currFree = (suballoc.type == SUBALLOCATION_TYPE_FREE);
  3448. const Allocation* alloc = (Allocation*)suballoc.privateData;
  3449. if (!IsVirtual())
  3450. {
  3451. D3D12MA_VALIDATE(currFree == (alloc == NULL));
  3452. }
  3453. D3D12MA_VALIDATE(suballoc.offset >= offset);
  3454. D3D12MA_VALIDATE(i >= m_1stNullItemsBeginCount || currFree);
  3455. if (!currFree)
  3456. {
  3457. if (!IsVirtual())
  3458. {
  3459. D3D12MA_VALIDATE(GetAllocationOffset(alloc->GetAllocHandle()) == suballoc.offset);
  3460. D3D12MA_VALIDATE(alloc->GetSize() == suballoc.size);
  3461. }
  3462. sumUsedSize += suballoc.size;
  3463. }
  3464. else
  3465. {
  3466. ++nullItem1stCount;
  3467. }
  3468. offset = suballoc.offset + suballoc.size + GetDebugMargin();
  3469. }
  3470. D3D12MA_VALIDATE(nullItem1stCount == m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount);
  3471. if (m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
  3472. {
  3473. const size_t suballoc2ndCount = suballocations2nd.size();
  3474. size_t nullItem2ndCount = 0;
  3475. for (size_t i = suballoc2ndCount; i--; )
  3476. {
  3477. const Suballocation& suballoc = suballocations2nd[i];
  3478. const bool currFree = (suballoc.type == SUBALLOCATION_TYPE_FREE);
  3479. const Allocation* alloc = (Allocation*)suballoc.privateData;
  3480. if (!IsVirtual())
  3481. {
  3482. D3D12MA_VALIDATE(currFree == (alloc == NULL));
  3483. }
  3484. D3D12MA_VALIDATE(suballoc.offset >= offset);
  3485. if (!currFree)
  3486. {
  3487. if (!IsVirtual())
  3488. {
  3489. D3D12MA_VALIDATE(GetAllocationOffset(alloc->GetAllocHandle()) == suballoc.offset);
  3490. D3D12MA_VALIDATE(alloc->GetSize() == suballoc.size);
  3491. }
  3492. sumUsedSize += suballoc.size;
  3493. }
  3494. else
  3495. {
  3496. ++nullItem2ndCount;
  3497. }
  3498. offset = suballoc.offset + suballoc.size + GetDebugMargin();
  3499. }
  3500. D3D12MA_VALIDATE(nullItem2ndCount == m_2ndNullItemsCount);
  3501. }
  3502. D3D12MA_VALIDATE(offset <= GetSize());
  3503. D3D12MA_VALIDATE(m_SumFreeSize == GetSize() - sumUsedSize);
  3504. return true;
  3505. }
  3506. size_t BlockMetadata_Linear::GetAllocationCount() const
  3507. {
  3508. return AccessSuballocations1st().size() - m_1stNullItemsBeginCount - m_1stNullItemsMiddleCount +
  3509. AccessSuballocations2nd().size() - m_2ndNullItemsCount;
  3510. }
  3511. size_t BlockMetadata_Linear::GetFreeRegionsCount() const
  3512. {
  3513. // Function only used for defragmentation, which is disabled for this algorithm
  3514. D3D12MA_ASSERT(0);
  3515. return SIZE_MAX;
  3516. }
  3517. void BlockMetadata_Linear::GetAllocationInfo(AllocHandle allocHandle, VIRTUAL_ALLOCATION_INFO& outInfo) const
  3518. {
  3519. const Suballocation& suballoc = FindSuballocation((UINT64)allocHandle - 1);
  3520. outInfo.Offset = suballoc.offset;
  3521. outInfo.Size = suballoc.size;
  3522. outInfo.pPrivateData = suballoc.privateData;
  3523. }
  3524. bool BlockMetadata_Linear::CreateAllocationRequest(
  3525. UINT64 allocSize,
  3526. UINT64 allocAlignment,
  3527. bool upperAddress,
  3528. UINT32 strategy,
  3529. AllocationRequest* pAllocationRequest)
  3530. {
  3531. D3D12MA_ASSERT(allocSize > 0 && "Cannot allocate empty block!");
  3532. D3D12MA_ASSERT(pAllocationRequest != NULL);
  3533. D3D12MA_HEAVY_ASSERT(Validate());
  3534. pAllocationRequest->size = allocSize;
  3535. return upperAddress ?
  3536. CreateAllocationRequest_UpperAddress(
  3537. allocSize, allocAlignment, pAllocationRequest) :
  3538. CreateAllocationRequest_LowerAddress(
  3539. allocSize, allocAlignment, pAllocationRequest);
  3540. }
  3541. void BlockMetadata_Linear::Alloc(
  3542. const AllocationRequest& request,
  3543. UINT64 allocSize,
  3544. void* privateData)
  3545. {
  3546. UINT64 offset = (UINT64)request.allocHandle - 1;
  3547. const Suballocation newSuballoc = { offset, request.size, privateData, SUBALLOCATION_TYPE_ALLOCATION };
  3548. switch (request.algorithmData)
  3549. {
  3550. case ALLOC_REQUEST_UPPER_ADDRESS:
  3551. {
  3552. D3D12MA_ASSERT(m_2ndVectorMode != SECOND_VECTOR_RING_BUFFER &&
  3553. "CRITICAL ERROR: Trying to use linear allocator as double stack while it was already used as ring buffer.");
  3554. SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
  3555. suballocations2nd.push_back(newSuballoc);
  3556. m_2ndVectorMode = SECOND_VECTOR_DOUBLE_STACK;
  3557. break;
  3558. }
  3559. case ALLOC_REQUEST_END_OF_1ST:
  3560. {
  3561. SuballocationVectorType& suballocations1st = AccessSuballocations1st();
  3562. D3D12MA_ASSERT(suballocations1st.empty() ||
  3563. offset >= suballocations1st.back().offset + suballocations1st.back().size);
  3564. // Check if it fits before the end of the block.
  3565. D3D12MA_ASSERT(offset + request.size <= GetSize());
  3566. suballocations1st.push_back(newSuballoc);
  3567. break;
  3568. }
  3569. case ALLOC_REQUEST_END_OF_2ND:
  3570. {
  3571. SuballocationVectorType& suballocations1st = AccessSuballocations1st();
  3572. // New allocation at the end of 2-part ring buffer, so before first allocation from 1st vector.
  3573. D3D12MA_ASSERT(!suballocations1st.empty() &&
  3574. offset + request.size <= suballocations1st[m_1stNullItemsBeginCount].offset);
  3575. SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
  3576. switch (m_2ndVectorMode)
  3577. {
  3578. case SECOND_VECTOR_EMPTY:
  3579. // First allocation from second part ring buffer.
  3580. D3D12MA_ASSERT(suballocations2nd.empty());
  3581. m_2ndVectorMode = SECOND_VECTOR_RING_BUFFER;
  3582. break;
  3583. case SECOND_VECTOR_RING_BUFFER:
  3584. // 2-part ring buffer is already started.
  3585. D3D12MA_ASSERT(!suballocations2nd.empty());
  3586. break;
  3587. case SECOND_VECTOR_DOUBLE_STACK:
  3588. D3D12MA_ASSERT(0 && "CRITICAL ERROR: Trying to use linear allocator as ring buffer while it was already used as double stack.");
  3589. break;
  3590. default:
  3591. D3D12MA_ASSERT(0);
  3592. }
  3593. suballocations2nd.push_back(newSuballoc);
  3594. break;
  3595. }
  3596. default:
  3597. D3D12MA_ASSERT(0 && "CRITICAL INTERNAL ERROR.");
  3598. }
  3599. m_SumFreeSize -= newSuballoc.size;
  3600. }
  3601. void BlockMetadata_Linear::Free(AllocHandle allocHandle)
  3602. {
  3603. SuballocationVectorType& suballocations1st = AccessSuballocations1st();
  3604. SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
  3605. UINT64 offset = (UINT64)allocHandle - 1;
  3606. if (!suballocations1st.empty())
  3607. {
  3608. // First allocation: Mark it as next empty at the beginning.
  3609. Suballocation& firstSuballoc = suballocations1st[m_1stNullItemsBeginCount];
  3610. if (firstSuballoc.offset == offset)
  3611. {
  3612. firstSuballoc.type = SUBALLOCATION_TYPE_FREE;
  3613. firstSuballoc.privateData = NULL;
  3614. m_SumFreeSize += firstSuballoc.size;
  3615. ++m_1stNullItemsBeginCount;
  3616. CleanupAfterFree();
  3617. return;
  3618. }
  3619. }
  3620. // Last allocation in 2-part ring buffer or top of upper stack (same logic).
  3621. if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER ||
  3622. m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
  3623. {
  3624. Suballocation& lastSuballoc = suballocations2nd.back();
  3625. if (lastSuballoc.offset == offset)
  3626. {
  3627. m_SumFreeSize += lastSuballoc.size;
  3628. suballocations2nd.pop_back();
  3629. CleanupAfterFree();
  3630. return;
  3631. }
  3632. }
  3633. // Last allocation in 1st vector.
  3634. else if (m_2ndVectorMode == SECOND_VECTOR_EMPTY)
  3635. {
  3636. Suballocation& lastSuballoc = suballocations1st.back();
  3637. if (lastSuballoc.offset == offset)
  3638. {
  3639. m_SumFreeSize += lastSuballoc.size;
  3640. suballocations1st.pop_back();
  3641. CleanupAfterFree();
  3642. return;
  3643. }
  3644. }
  3645. Suballocation refSuballoc;
  3646. refSuballoc.offset = offset;
  3647. // Rest of members stays uninitialized intentionally for better performance.
  3648. // Item from the middle of 1st vector.
  3649. {
  3650. const SuballocationVectorType::iterator it = BinaryFindSorted(
  3651. suballocations1st.begin() + m_1stNullItemsBeginCount,
  3652. suballocations1st.end(),
  3653. refSuballoc,
  3654. SuballocationOffsetLess());
  3655. if (it != suballocations1st.end())
  3656. {
  3657. it->type = SUBALLOCATION_TYPE_FREE;
  3658. it->privateData = NULL;
  3659. ++m_1stNullItemsMiddleCount;
  3660. m_SumFreeSize += it->size;
  3661. CleanupAfterFree();
  3662. return;
  3663. }
  3664. }
  3665. if (m_2ndVectorMode != SECOND_VECTOR_EMPTY)
  3666. {
  3667. // Item from the middle of 2nd vector.
  3668. const SuballocationVectorType::iterator it = m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER ?
  3669. BinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, SuballocationOffsetLess()) :
  3670. BinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, SuballocationOffsetGreater());
  3671. if (it != suballocations2nd.end())
  3672. {
  3673. it->type = SUBALLOCATION_TYPE_FREE;
  3674. it->privateData = NULL;
  3675. ++m_2ndNullItemsCount;
  3676. m_SumFreeSize += it->size;
  3677. CleanupAfterFree();
  3678. return;
  3679. }
  3680. }
  3681. D3D12MA_ASSERT(0 && "Allocation to free not found in linear allocator!");
  3682. }
  3683. void BlockMetadata_Linear::Clear()
  3684. {
  3685. m_SumFreeSize = GetSize();
  3686. m_Suballocations0.clear();
  3687. m_Suballocations1.clear();
  3688. // Leaving m_1stVectorIndex unchanged - it doesn't matter.
  3689. m_2ndVectorMode = SECOND_VECTOR_EMPTY;
  3690. m_1stNullItemsBeginCount = 0;
  3691. m_1stNullItemsMiddleCount = 0;
  3692. m_2ndNullItemsCount = 0;
  3693. }
  3694. AllocHandle BlockMetadata_Linear::GetAllocationListBegin() const
  3695. {
  3696. // Function only used for defragmentation, which is disabled for this algorithm
  3697. D3D12MA_ASSERT(0);
  3698. return (AllocHandle)0;
  3699. }
  3700. AllocHandle BlockMetadata_Linear::GetNextAllocation(AllocHandle prevAlloc) const
  3701. {
  3702. // Function only used for defragmentation, which is disabled for this algorithm
  3703. D3D12MA_ASSERT(0);
  3704. return (AllocHandle)0;
  3705. }
  3706. UINT64 BlockMetadata_Linear::GetNextFreeRegionSize(AllocHandle alloc) const
  3707. {
  3708. // Function only used for defragmentation, which is disabled for this algorithm
  3709. D3D12MA_ASSERT(0);
  3710. return 0;
  3711. }
  3712. void* BlockMetadata_Linear::GetAllocationPrivateData(AllocHandle allocHandle) const
  3713. {
  3714. return FindSuballocation((UINT64)allocHandle - 1).privateData;
  3715. }
  3716. void BlockMetadata_Linear::SetAllocationPrivateData(AllocHandle allocHandle, void* privateData)
  3717. {
  3718. Suballocation& suballoc = FindSuballocation((UINT64)allocHandle - 1);
  3719. suballoc.privateData = privateData;
  3720. }
  3721. void BlockMetadata_Linear::AddStatistics(Statistics& inoutStats) const
  3722. {
  3723. inoutStats.BlockCount++;
  3724. inoutStats.AllocationCount += (UINT)GetAllocationCount();
  3725. inoutStats.BlockBytes += GetSize();
  3726. inoutStats.AllocationBytes += GetSize() - m_SumFreeSize;
  3727. }
  3728. void BlockMetadata_Linear::AddDetailedStatistics(DetailedStatistics& inoutStats) const
  3729. {
  3730. inoutStats.Stats.BlockCount++;
  3731. inoutStats.Stats.BlockBytes += GetSize();
  3732. const UINT64 size = GetSize();
  3733. const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
  3734. const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
  3735. const size_t suballoc1stCount = suballocations1st.size();
  3736. const size_t suballoc2ndCount = suballocations2nd.size();
  3737. UINT64 lastOffset = 0;
  3738. if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
  3739. {
  3740. const UINT64 freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
  3741. size_t nextAlloc2ndIndex = 0;
  3742. while (lastOffset < freeSpace2ndTo1stEnd)
  3743. {
  3744. // Find next non-null allocation or move nextAllocIndex to the end.
  3745. while (nextAlloc2ndIndex < suballoc2ndCount &&
  3746. suballocations2nd[nextAlloc2ndIndex].privateData == NULL)
  3747. {
  3748. ++nextAlloc2ndIndex;
  3749. }
  3750. // Found non-null allocation.
  3751. if (nextAlloc2ndIndex < suballoc2ndCount)
  3752. {
  3753. const Suballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
  3754. // 1. Process free space before this allocation.
  3755. if (lastOffset < suballoc.offset)
  3756. {
  3757. // There is free space from lastOffset to suballoc.offset.
  3758. const UINT64 unusedRangeSize = suballoc.offset - lastOffset;
  3759. AddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize);
  3760. }
  3761. // 2. Process this allocation.
  3762. // There is allocation with suballoc.offset, suballoc.size.
  3763. AddDetailedStatisticsAllocation(inoutStats, suballoc.size);
  3764. // 3. Prepare for next iteration.
  3765. lastOffset = suballoc.offset + suballoc.size;
  3766. ++nextAlloc2ndIndex;
  3767. }
  3768. // We are at the end.
  3769. else
  3770. {
  3771. // There is free space from lastOffset to freeSpace2ndTo1stEnd.
  3772. if (lastOffset < freeSpace2ndTo1stEnd)
  3773. {
  3774. const UINT64 unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset;
  3775. AddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize);
  3776. }
  3777. // End of loop.
  3778. lastOffset = freeSpace2ndTo1stEnd;
  3779. }
  3780. }
  3781. }
  3782. size_t nextAlloc1stIndex = m_1stNullItemsBeginCount;
  3783. const UINT64 freeSpace1stTo2ndEnd =
  3784. m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size;
  3785. while (lastOffset < freeSpace1stTo2ndEnd)
  3786. {
  3787. // Find next non-null allocation or move nextAllocIndex to the end.
  3788. while (nextAlloc1stIndex < suballoc1stCount &&
  3789. suballocations1st[nextAlloc1stIndex].privateData == NULL)
  3790. {
  3791. ++nextAlloc1stIndex;
  3792. }
  3793. // Found non-null allocation.
  3794. if (nextAlloc1stIndex < suballoc1stCount)
  3795. {
  3796. const Suballocation& suballoc = suballocations1st[nextAlloc1stIndex];
  3797. // 1. Process free space before this allocation.
  3798. if (lastOffset < suballoc.offset)
  3799. {
  3800. // There is free space from lastOffset to suballoc.offset.
  3801. const UINT64 unusedRangeSize = suballoc.offset - lastOffset;
  3802. AddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize);
  3803. }
  3804. // 2. Process this allocation.
  3805. // There is allocation with suballoc.offset, suballoc.size.
  3806. AddDetailedStatisticsAllocation(inoutStats, suballoc.size);
  3807. // 3. Prepare for next iteration.
  3808. lastOffset = suballoc.offset + suballoc.size;
  3809. ++nextAlloc1stIndex;
  3810. }
  3811. // We are at the end.
  3812. else
  3813. {
  3814. // There is free space from lastOffset to freeSpace1stTo2ndEnd.
  3815. if (lastOffset < freeSpace1stTo2ndEnd)
  3816. {
  3817. const UINT64 unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset;
  3818. AddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize);
  3819. }
  3820. // End of loop.
  3821. lastOffset = freeSpace1stTo2ndEnd;
  3822. }
  3823. }
  3824. if (m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
  3825. {
  3826. size_t nextAlloc2ndIndex = suballocations2nd.size() - 1;
  3827. while (lastOffset < size)
  3828. {
  3829. // Find next non-null allocation or move nextAllocIndex to the end.
  3830. while (nextAlloc2ndIndex != SIZE_MAX &&
  3831. suballocations2nd[nextAlloc2ndIndex].privateData == NULL)
  3832. {
  3833. --nextAlloc2ndIndex;
  3834. }
  3835. // Found non-null allocation.
  3836. if (nextAlloc2ndIndex != SIZE_MAX)
  3837. {
  3838. const Suballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
  3839. // 1. Process free space before this allocation.
  3840. if (lastOffset < suballoc.offset)
  3841. {
  3842. // There is free space from lastOffset to suballoc.offset.
  3843. const UINT64 unusedRangeSize = suballoc.offset - lastOffset;
  3844. AddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize);
  3845. }
  3846. // 2. Process this allocation.
  3847. // There is allocation with suballoc.offset, suballoc.size.
  3848. AddDetailedStatisticsAllocation(inoutStats, suballoc.size);
  3849. // 3. Prepare for next iteration.
  3850. lastOffset = suballoc.offset + suballoc.size;
  3851. --nextAlloc2ndIndex;
  3852. }
  3853. // We are at the end.
  3854. else
  3855. {
  3856. // There is free space from lastOffset to size.
  3857. if (lastOffset < size)
  3858. {
  3859. const UINT64 unusedRangeSize = size - lastOffset;
  3860. AddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize);
  3861. }
  3862. // End of loop.
  3863. lastOffset = size;
  3864. }
  3865. }
  3866. }
  3867. }
  3868. void BlockMetadata_Linear::WriteAllocationInfoToJson(JsonWriter& json) const
  3869. {
  3870. const UINT64 size = GetSize();
  3871. const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
  3872. const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
  3873. const size_t suballoc1stCount = suballocations1st.size();
  3874. const size_t suballoc2ndCount = suballocations2nd.size();
  3875. // FIRST PASS
  3876. size_t unusedRangeCount = 0;
  3877. UINT64 usedBytes = 0;
  3878. UINT64 lastOffset = 0;
  3879. size_t alloc2ndCount = 0;
  3880. if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
  3881. {
  3882. const UINT64 freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
  3883. size_t nextAlloc2ndIndex = 0;
  3884. while (lastOffset < freeSpace2ndTo1stEnd)
  3885. {
  3886. // Find next non-null allocation or move nextAlloc2ndIndex to the end.
  3887. while (nextAlloc2ndIndex < suballoc2ndCount &&
  3888. suballocations2nd[nextAlloc2ndIndex].privateData == NULL)
  3889. {
  3890. ++nextAlloc2ndIndex;
  3891. }
  3892. // Found non-null allocation.
  3893. if (nextAlloc2ndIndex < suballoc2ndCount)
  3894. {
  3895. const Suballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
  3896. // 1. Process free space before this allocation.
  3897. if (lastOffset < suballoc.offset)
  3898. {
  3899. // There is free space from lastOffset to suballoc.offset.
  3900. ++unusedRangeCount;
  3901. }
  3902. // 2. Process this allocation.
  3903. // There is allocation with suballoc.offset, suballoc.size.
  3904. ++alloc2ndCount;
  3905. usedBytes += suballoc.size;
  3906. // 3. Prepare for next iteration.
  3907. lastOffset = suballoc.offset + suballoc.size;
  3908. ++nextAlloc2ndIndex;
  3909. }
  3910. // We are at the end.
  3911. else
  3912. {
  3913. if (lastOffset < freeSpace2ndTo1stEnd)
  3914. {
  3915. // There is free space from lastOffset to freeSpace2ndTo1stEnd.
  3916. ++unusedRangeCount;
  3917. }
  3918. // End of loop.
  3919. lastOffset = freeSpace2ndTo1stEnd;
  3920. }
  3921. }
  3922. }
  3923. size_t nextAlloc1stIndex = m_1stNullItemsBeginCount;
  3924. size_t alloc1stCount = 0;
  3925. const UINT64 freeSpace1stTo2ndEnd =
  3926. m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size;
  3927. while (lastOffset < freeSpace1stTo2ndEnd)
  3928. {
  3929. // Find next non-null allocation or move nextAllocIndex to the end.
  3930. while (nextAlloc1stIndex < suballoc1stCount &&
  3931. suballocations1st[nextAlloc1stIndex].privateData == NULL)
  3932. {
  3933. ++nextAlloc1stIndex;
  3934. }
  3935. // Found non-null allocation.
  3936. if (nextAlloc1stIndex < suballoc1stCount)
  3937. {
  3938. const Suballocation& suballoc = suballocations1st[nextAlloc1stIndex];
  3939. // 1. Process free space before this allocation.
  3940. if (lastOffset < suballoc.offset)
  3941. {
  3942. // There is free space from lastOffset to suballoc.offset.
  3943. ++unusedRangeCount;
  3944. }
  3945. // 2. Process this allocation.
  3946. // There is allocation with suballoc.offset, suballoc.size.
  3947. ++alloc1stCount;
  3948. usedBytes += suballoc.size;
  3949. // 3. Prepare for next iteration.
  3950. lastOffset = suballoc.offset + suballoc.size;
  3951. ++nextAlloc1stIndex;
  3952. }
  3953. // We are at the end.
  3954. else
  3955. {
  3956. if (lastOffset < size)
  3957. {
  3958. // There is free space from lastOffset to freeSpace1stTo2ndEnd.
  3959. ++unusedRangeCount;
  3960. }
  3961. // End of loop.
  3962. lastOffset = freeSpace1stTo2ndEnd;
  3963. }
  3964. }
  3965. if (m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
  3966. {
  3967. size_t nextAlloc2ndIndex = suballocations2nd.size() - 1;
  3968. while (lastOffset < size)
  3969. {
  3970. // Find next non-null allocation or move nextAlloc2ndIndex to the end.
  3971. while (nextAlloc2ndIndex != SIZE_MAX &&
  3972. suballocations2nd[nextAlloc2ndIndex].privateData == NULL)
  3973. {
  3974. --nextAlloc2ndIndex;
  3975. }
  3976. // Found non-null allocation.
  3977. if (nextAlloc2ndIndex != SIZE_MAX)
  3978. {
  3979. const Suballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
  3980. // 1. Process free space before this allocation.
  3981. if (lastOffset < suballoc.offset)
  3982. {
  3983. // There is free space from lastOffset to suballoc.offset.
  3984. ++unusedRangeCount;
  3985. }
  3986. // 2. Process this allocation.
  3987. // There is allocation with suballoc.offset, suballoc.size.
  3988. ++alloc2ndCount;
  3989. usedBytes += suballoc.size;
  3990. // 3. Prepare for next iteration.
  3991. lastOffset = suballoc.offset + suballoc.size;
  3992. --nextAlloc2ndIndex;
  3993. }
  3994. // We are at the end.
  3995. else
  3996. {
  3997. if (lastOffset < size)
  3998. {
  3999. // There is free space from lastOffset to size.
  4000. ++unusedRangeCount;
  4001. }
  4002. // End of loop.
  4003. lastOffset = size;
  4004. }
  4005. }
  4006. }
  4007. const UINT64 unusedBytes = size - usedBytes;
  4008. PrintDetailedMap_Begin(json, unusedBytes, alloc1stCount + alloc2ndCount, unusedRangeCount);
  4009. // SECOND PASS
  4010. lastOffset = 0;
  4011. if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
  4012. {
  4013. const UINT64 freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
  4014. size_t nextAlloc2ndIndex = 0;
  4015. while (lastOffset < freeSpace2ndTo1stEnd)
  4016. {
  4017. // Find next non-null allocation or move nextAlloc2ndIndex to the end.
  4018. while (nextAlloc2ndIndex < suballoc2ndCount &&
  4019. suballocations2nd[nextAlloc2ndIndex].privateData == NULL)
  4020. {
  4021. ++nextAlloc2ndIndex;
  4022. }
  4023. // Found non-null allocation.
  4024. if (nextAlloc2ndIndex < suballoc2ndCount)
  4025. {
  4026. const Suballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
  4027. // 1. Process free space before this allocation.
  4028. if (lastOffset < suballoc.offset)
  4029. {
  4030. // There is free space from lastOffset to suballoc.offset.
  4031. const UINT64 unusedRangeSize = suballoc.offset - lastOffset;
  4032. PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
  4033. }
  4034. // 2. Process this allocation.
  4035. // There is allocation with suballoc.offset, suballoc.size.
  4036. PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.privateData);
  4037. // 3. Prepare for next iteration.
  4038. lastOffset = suballoc.offset + suballoc.size;
  4039. ++nextAlloc2ndIndex;
  4040. }
  4041. // We are at the end.
  4042. else
  4043. {
  4044. if (lastOffset < freeSpace2ndTo1stEnd)
  4045. {
  4046. // There is free space from lastOffset to freeSpace2ndTo1stEnd.
  4047. const UINT64 unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset;
  4048. PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
  4049. }
  4050. // End of loop.
  4051. lastOffset = freeSpace2ndTo1stEnd;
  4052. }
  4053. }
  4054. }
  4055. nextAlloc1stIndex = m_1stNullItemsBeginCount;
  4056. while (lastOffset < freeSpace1stTo2ndEnd)
  4057. {
  4058. // Find next non-null allocation or move nextAllocIndex to the end.
  4059. while (nextAlloc1stIndex < suballoc1stCount &&
  4060. suballocations1st[nextAlloc1stIndex].privateData == NULL)
  4061. {
  4062. ++nextAlloc1stIndex;
  4063. }
  4064. // Found non-null allocation.
  4065. if (nextAlloc1stIndex < suballoc1stCount)
  4066. {
  4067. const Suballocation& suballoc = suballocations1st[nextAlloc1stIndex];
  4068. // 1. Process free space before this allocation.
  4069. if (lastOffset < suballoc.offset)
  4070. {
  4071. // There is free space from lastOffset to suballoc.offset.
  4072. const UINT64 unusedRangeSize = suballoc.offset - lastOffset;
  4073. PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
  4074. }
  4075. // 2. Process this allocation.
  4076. // There is allocation with suballoc.offset, suballoc.size.
  4077. PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.privateData);
  4078. // 3. Prepare for next iteration.
  4079. lastOffset = suballoc.offset + suballoc.size;
  4080. ++nextAlloc1stIndex;
  4081. }
  4082. // We are at the end.
  4083. else
  4084. {
  4085. if (lastOffset < freeSpace1stTo2ndEnd)
  4086. {
  4087. // There is free space from lastOffset to freeSpace1stTo2ndEnd.
  4088. const UINT64 unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset;
  4089. PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
  4090. }
  4091. // End of loop.
  4092. lastOffset = freeSpace1stTo2ndEnd;
  4093. }
  4094. }
  4095. if (m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
  4096. {
  4097. size_t nextAlloc2ndIndex = suballocations2nd.size() - 1;
  4098. while (lastOffset < size)
  4099. {
  4100. // Find next non-null allocation or move nextAlloc2ndIndex to the end.
  4101. while (nextAlloc2ndIndex != SIZE_MAX &&
  4102. suballocations2nd[nextAlloc2ndIndex].privateData == NULL)
  4103. {
  4104. --nextAlloc2ndIndex;
  4105. }
  4106. // Found non-null allocation.
  4107. if (nextAlloc2ndIndex != SIZE_MAX)
  4108. {
  4109. const Suballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
  4110. // 1. Process free space before this allocation.
  4111. if (lastOffset < suballoc.offset)
  4112. {
  4113. // There is free space from lastOffset to suballoc.offset.
  4114. const UINT64 unusedRangeSize = suballoc.offset - lastOffset;
  4115. PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
  4116. }
  4117. // 2. Process this allocation.
  4118. // There is allocation with suballoc.offset, suballoc.size.
  4119. PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.privateData);
  4120. // 3. Prepare for next iteration.
  4121. lastOffset = suballoc.offset + suballoc.size;
  4122. --nextAlloc2ndIndex;
  4123. }
  4124. // We are at the end.
  4125. else
  4126. {
  4127. if (lastOffset < size)
  4128. {
  4129. // There is free space from lastOffset to size.
  4130. const UINT64 unusedRangeSize = size - lastOffset;
  4131. PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
  4132. }
  4133. // End of loop.
  4134. lastOffset = size;
  4135. }
  4136. }
  4137. }
  4138. PrintDetailedMap_End(json);
  4139. }
  4140. void BlockMetadata_Linear::DebugLogAllAllocations() const
  4141. {
  4142. const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
  4143. for (auto it = suballocations1st.begin() + m_1stNullItemsBeginCount; it != suballocations1st.end(); ++it)
  4144. if (it->type != SUBALLOCATION_TYPE_FREE)
  4145. DebugLogAllocation(it->offset, it->size, it->privateData);
  4146. const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
  4147. for (auto it = suballocations2nd.begin(); it != suballocations2nd.end(); ++it)
  4148. if (it->type != SUBALLOCATION_TYPE_FREE)
  4149. DebugLogAllocation(it->offset, it->size, it->privateData);
  4150. }
  4151. Suballocation& BlockMetadata_Linear::FindSuballocation(UINT64 offset) const
  4152. {
  4153. const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
  4154. const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
  4155. Suballocation refSuballoc;
  4156. refSuballoc.offset = offset;
  4157. // Rest of members stays uninitialized intentionally for better performance.
  4158. // Item from the 1st vector.
  4159. {
  4160. const SuballocationVectorType::const_iterator it = BinaryFindSorted(
  4161. suballocations1st.begin() + m_1stNullItemsBeginCount,
  4162. suballocations1st.end(),
  4163. refSuballoc,
  4164. SuballocationOffsetLess());
  4165. if (it != suballocations1st.end())
  4166. {
  4167. return const_cast<Suballocation&>(*it);
  4168. }
  4169. }
  4170. if (m_2ndVectorMode != SECOND_VECTOR_EMPTY)
  4171. {
  4172. // Rest of members stays uninitialized intentionally for better performance.
  4173. const SuballocationVectorType::const_iterator it = m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER ?
  4174. BinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, SuballocationOffsetLess()) :
  4175. BinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, SuballocationOffsetGreater());
  4176. if (it != suballocations2nd.end())
  4177. {
  4178. return const_cast<Suballocation&>(*it);
  4179. }
  4180. }
  4181. D3D12MA_ASSERT(0 && "Allocation not found in linear allocator!");
  4182. return const_cast<Suballocation&>(suballocations1st.back()); // Should never occur.
  4183. }
  4184. bool BlockMetadata_Linear::ShouldCompact1st() const
  4185. {
  4186. const size_t nullItemCount = m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount;
  4187. const size_t suballocCount = AccessSuballocations1st().size();
  4188. return suballocCount > 32 && nullItemCount * 2 >= (suballocCount - nullItemCount) * 3;
  4189. }
  4190. void BlockMetadata_Linear::CleanupAfterFree()
  4191. {
  4192. SuballocationVectorType& suballocations1st = AccessSuballocations1st();
  4193. SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
  4194. if (IsEmpty())
  4195. {
  4196. suballocations1st.clear();
  4197. suballocations2nd.clear();
  4198. m_1stNullItemsBeginCount = 0;
  4199. m_1stNullItemsMiddleCount = 0;
  4200. m_2ndNullItemsCount = 0;
  4201. m_2ndVectorMode = SECOND_VECTOR_EMPTY;
  4202. }
  4203. else
  4204. {
  4205. const size_t suballoc1stCount = suballocations1st.size();
  4206. const size_t nullItem1stCount = m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount;
  4207. D3D12MA_ASSERT(nullItem1stCount <= suballoc1stCount);
  4208. // Find more null items at the beginning of 1st vector.
  4209. while (m_1stNullItemsBeginCount < suballoc1stCount &&
  4210. suballocations1st[m_1stNullItemsBeginCount].type == SUBALLOCATION_TYPE_FREE)
  4211. {
  4212. ++m_1stNullItemsBeginCount;
  4213. --m_1stNullItemsMiddleCount;
  4214. }
  4215. // Find more null items at the end of 1st vector.
  4216. while (m_1stNullItemsMiddleCount > 0 &&
  4217. suballocations1st.back().type == SUBALLOCATION_TYPE_FREE)
  4218. {
  4219. --m_1stNullItemsMiddleCount;
  4220. suballocations1st.pop_back();
  4221. }
  4222. // Find more null items at the end of 2nd vector.
  4223. while (m_2ndNullItemsCount > 0 &&
  4224. suballocations2nd.back().type == SUBALLOCATION_TYPE_FREE)
  4225. {
  4226. --m_2ndNullItemsCount;
  4227. suballocations2nd.pop_back();
  4228. }
  4229. // Find more null items at the beginning of 2nd vector.
  4230. while (m_2ndNullItemsCount > 0 &&
  4231. suballocations2nd[0].type == SUBALLOCATION_TYPE_FREE)
  4232. {
  4233. --m_2ndNullItemsCount;
  4234. suballocations2nd.remove(0);
  4235. }
  4236. if (ShouldCompact1st())
  4237. {
  4238. const size_t nonNullItemCount = suballoc1stCount - nullItem1stCount;
  4239. size_t srcIndex = m_1stNullItemsBeginCount;
  4240. for (size_t dstIndex = 0; dstIndex < nonNullItemCount; ++dstIndex)
  4241. {
  4242. while (suballocations1st[srcIndex].type == SUBALLOCATION_TYPE_FREE)
  4243. {
  4244. ++srcIndex;
  4245. }
  4246. if (dstIndex != srcIndex)
  4247. {
  4248. suballocations1st[dstIndex] = suballocations1st[srcIndex];
  4249. }
  4250. ++srcIndex;
  4251. }
  4252. suballocations1st.resize(nonNullItemCount);
  4253. m_1stNullItemsBeginCount = 0;
  4254. m_1stNullItemsMiddleCount = 0;
  4255. }
  4256. // 2nd vector became empty.
  4257. if (suballocations2nd.empty())
  4258. {
  4259. m_2ndVectorMode = SECOND_VECTOR_EMPTY;
  4260. }
  4261. // 1st vector became empty.
  4262. if (suballocations1st.size() - m_1stNullItemsBeginCount == 0)
  4263. {
  4264. suballocations1st.clear();
  4265. m_1stNullItemsBeginCount = 0;
  4266. if (!suballocations2nd.empty() && m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
  4267. {
  4268. // Swap 1st with 2nd. Now 2nd is empty.
  4269. m_2ndVectorMode = SECOND_VECTOR_EMPTY;
  4270. m_1stNullItemsMiddleCount = m_2ndNullItemsCount;
  4271. while (m_1stNullItemsBeginCount < suballocations2nd.size() &&
  4272. suballocations2nd[m_1stNullItemsBeginCount].type == SUBALLOCATION_TYPE_FREE)
  4273. {
  4274. ++m_1stNullItemsBeginCount;
  4275. --m_1stNullItemsMiddleCount;
  4276. }
  4277. m_2ndNullItemsCount = 0;
  4278. m_1stVectorIndex ^= 1;
  4279. }
  4280. }
  4281. }
  4282. D3D12MA_HEAVY_ASSERT(Validate());
  4283. }
  4284. bool BlockMetadata_Linear::CreateAllocationRequest_LowerAddress(
  4285. UINT64 allocSize,
  4286. UINT64 allocAlignment,
  4287. AllocationRequest* pAllocationRequest)
  4288. {
  4289. const UINT64 blockSize = GetSize();
  4290. SuballocationVectorType& suballocations1st = AccessSuballocations1st();
  4291. SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
  4292. if (m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
  4293. {
  4294. // Try to allocate at the end of 1st vector.
  4295. UINT64 resultBaseOffset = 0;
  4296. if (!suballocations1st.empty())
  4297. {
  4298. const Suballocation& lastSuballoc = suballocations1st.back();
  4299. resultBaseOffset = lastSuballoc.offset + lastSuballoc.size + GetDebugMargin();
  4300. }
  4301. // Start from offset equal to beginning of free space.
  4302. UINT64 resultOffset = resultBaseOffset;
  4303. // Apply alignment.
  4304. resultOffset = AlignUp(resultOffset, allocAlignment);
  4305. const UINT64 freeSpaceEnd = m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ?
  4306. suballocations2nd.back().offset : blockSize;
  4307. // There is enough free space at the end after alignment.
  4308. if (resultOffset + allocSize + GetDebugMargin() <= freeSpaceEnd)
  4309. {
  4310. // All tests passed: Success.
  4311. pAllocationRequest->allocHandle = (AllocHandle)(resultOffset + 1);
  4312. // pAllocationRequest->item, customData unused.
  4313. pAllocationRequest->algorithmData = ALLOC_REQUEST_END_OF_1ST;
  4314. return true;
  4315. }
  4316. }
  4317. // Wrap-around to end of 2nd vector. Try to allocate there, watching for the
  4318. // beginning of 1st vector as the end of free space.
  4319. if (m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
  4320. {
  4321. D3D12MA_ASSERT(!suballocations1st.empty());
  4322. UINT64 resultBaseOffset = 0;
  4323. if (!suballocations2nd.empty())
  4324. {
  4325. const Suballocation& lastSuballoc = suballocations2nd.back();
  4326. resultBaseOffset = lastSuballoc.offset + lastSuballoc.size + GetDebugMargin();
  4327. }
  4328. // Start from offset equal to beginning of free space.
  4329. UINT64 resultOffset = resultBaseOffset;
  4330. // Apply alignment.
  4331. resultOffset = AlignUp(resultOffset, allocAlignment);
  4332. size_t index1st = m_1stNullItemsBeginCount;
  4333. // There is enough free space at the end after alignment.
  4334. if ((index1st == suballocations1st.size() && resultOffset + allocSize + GetDebugMargin() <= blockSize) ||
  4335. (index1st < suballocations1st.size() && resultOffset + allocSize + GetDebugMargin() <= suballocations1st[index1st].offset))
  4336. {
  4337. // All tests passed: Success.
  4338. pAllocationRequest->allocHandle = (AllocHandle)(resultOffset + 1);
  4339. pAllocationRequest->algorithmData = ALLOC_REQUEST_END_OF_2ND;
  4340. // pAllocationRequest->item, customData unused.
  4341. return true;
  4342. }
  4343. }
  4344. return false;
  4345. }
  4346. bool BlockMetadata_Linear::CreateAllocationRequest_UpperAddress(
  4347. UINT64 allocSize,
  4348. UINT64 allocAlignment,
  4349. AllocationRequest* pAllocationRequest)
  4350. {
  4351. const UINT64 blockSize = GetSize();
  4352. SuballocationVectorType& suballocations1st = AccessSuballocations1st();
  4353. SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
  4354. if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
  4355. {
  4356. D3D12MA_ASSERT(0 && "Trying to use pool with linear algorithm as double stack, while it is already being used as ring buffer.");
  4357. return false;
  4358. }
  4359. // Try to allocate before 2nd.back(), or end of block if 2nd.empty().
  4360. if (allocSize > blockSize)
  4361. {
  4362. return false;
  4363. }
  4364. UINT64 resultBaseOffset = blockSize - allocSize;
  4365. if (!suballocations2nd.empty())
  4366. {
  4367. const Suballocation& lastSuballoc = suballocations2nd.back();
  4368. resultBaseOffset = lastSuballoc.offset - allocSize;
  4369. if (allocSize > lastSuballoc.offset)
  4370. {
  4371. return false;
  4372. }
  4373. }
  4374. // Start from offset equal to end of free space.
  4375. UINT64 resultOffset = resultBaseOffset;
  4376. // Apply debugMargin at the end.
  4377. if (GetDebugMargin() > 0)
  4378. {
  4379. if (resultOffset < GetDebugMargin())
  4380. {
  4381. return false;
  4382. }
  4383. resultOffset -= GetDebugMargin();
  4384. }
  4385. // Apply alignment.
  4386. resultOffset = AlignDown(resultOffset, allocAlignment);
  4387. // There is enough free space.
  4388. const UINT64 endOf1st = !suballocations1st.empty() ?
  4389. suballocations1st.back().offset + suballocations1st.back().size : 0;
  4390. if (endOf1st + GetDebugMargin() <= resultOffset)
  4391. {
  4392. // All tests passed: Success.
  4393. pAllocationRequest->allocHandle = (AllocHandle)(resultOffset + 1);
  4394. // pAllocationRequest->item unused.
  4395. pAllocationRequest->algorithmData = ALLOC_REQUEST_UPPER_ADDRESS;
  4396. return true;
  4397. }
  4398. return false;
  4399. }
  4400. #endif // _D3D12MA_BLOCK_METADATA_LINEAR_FUNCTIONS
  4401. #endif // _D3D12MA_BLOCK_METADATA_LINEAR
  4402. #ifndef _D3D12MA_BLOCK_METADATA_TLSF
  4403. class BlockMetadata_TLSF : public BlockMetadata
  4404. {
  4405. public:
  4406. BlockMetadata_TLSF(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual);
  4407. virtual ~BlockMetadata_TLSF();
  4408. size_t GetAllocationCount() const override { return m_AllocCount; }
  4409. size_t GetFreeRegionsCount() const override { return m_BlocksFreeCount + 1; }
  4410. UINT64 GetSumFreeSize() const override { return m_BlocksFreeSize + m_NullBlock->size; }
  4411. bool IsEmpty() const override { return m_NullBlock->offset == 0; }
  4412. UINT64 GetAllocationOffset(AllocHandle allocHandle) const override { return ((Block*)allocHandle)->offset; };
  4413. void Init(UINT64 size) override;
  4414. bool Validate() const override;
  4415. void GetAllocationInfo(AllocHandle allocHandle, VIRTUAL_ALLOCATION_INFO& outInfo) const override;
  4416. bool CreateAllocationRequest(
  4417. UINT64 allocSize,
  4418. UINT64 allocAlignment,
  4419. bool upperAddress,
  4420. UINT32 strategy,
  4421. AllocationRequest* pAllocationRequest) override;
  4422. void Alloc(
  4423. const AllocationRequest& request,
  4424. UINT64 allocSize,
  4425. void* privateData) override;
  4426. void Free(AllocHandle allocHandle) override;
  4427. void Clear() override;
  4428. AllocHandle GetAllocationListBegin() const override;
  4429. AllocHandle GetNextAllocation(AllocHandle prevAlloc) const override;
  4430. UINT64 GetNextFreeRegionSize(AllocHandle alloc) const override;
  4431. void* GetAllocationPrivateData(AllocHandle allocHandle) const override;
  4432. void SetAllocationPrivateData(AllocHandle allocHandle, void* privateData) override;
  4433. void AddStatistics(Statistics& inoutStats) const override;
  4434. void AddDetailedStatistics(DetailedStatistics& inoutStats) const override;
  4435. void WriteAllocationInfoToJson(JsonWriter& json) const override;
  4436. void DebugLogAllAllocations() const override;
  4437. private:
  4438. // According to original paper it should be preferable 4 or 5:
  4439. // M. Masmano, I. Ripoll, A. Crespo, and J. Real "TLSF: a New Dynamic Memory Allocator for Real-Time Systems"
  4440. // http://www.gii.upv.es/tlsf/files/ecrts04_tlsf.pdf
  4441. static const UINT8 SECOND_LEVEL_INDEX = 5;
  4442. static const UINT16 SMALL_BUFFER_SIZE = 256;
  4443. static const UINT INITIAL_BLOCK_ALLOC_COUNT = 16;
  4444. static const UINT8 MEMORY_CLASS_SHIFT = 7;
  4445. static const UINT8 MAX_MEMORY_CLASSES = 65 - MEMORY_CLASS_SHIFT;
  4446. class Block
  4447. {
  4448. public:
  4449. UINT64 offset;
  4450. UINT64 size;
  4451. Block* prevPhysical;
  4452. Block* nextPhysical;
  4453. void MarkFree() { prevFree = NULL; }
  4454. void MarkTaken() { prevFree = this; }
  4455. bool IsFree() const { return prevFree != this; }
  4456. void*& PrivateData() { D3D12MA_HEAVY_ASSERT(!IsFree()); return privateData; }
  4457. Block*& PrevFree() { return prevFree; }
  4458. Block*& NextFree() { D3D12MA_HEAVY_ASSERT(IsFree()); return nextFree; }
  4459. private:
  4460. Block* prevFree; // Address of the same block here indicates that block is taken
  4461. union
  4462. {
  4463. Block* nextFree;
  4464. void* privateData;
  4465. };
  4466. };
  4467. size_t m_AllocCount = 0;
  4468. // Total number of free blocks besides null block
  4469. size_t m_BlocksFreeCount = 0;
  4470. // Total size of free blocks excluding null block
  4471. UINT64 m_BlocksFreeSize = 0;
  4472. UINT32 m_IsFreeBitmap = 0;
  4473. UINT8 m_MemoryClasses = 0;
  4474. UINT32 m_InnerIsFreeBitmap[MAX_MEMORY_CLASSES];
  4475. UINT32 m_ListsCount = 0;
  4476. /*
  4477. * 0: 0-3 lists for small buffers
  4478. * 1+: 0-(2^SLI-1) lists for normal buffers
  4479. */
  4480. Block** m_FreeList = NULL;
  4481. PoolAllocator<Block> m_BlockAllocator;
  4482. Block* m_NullBlock = NULL;
  4483. UINT8 SizeToMemoryClass(UINT64 size) const;
  4484. UINT16 SizeToSecondIndex(UINT64 size, UINT8 memoryClass) const;
  4485. UINT32 GetListIndex(UINT8 memoryClass, UINT16 secondIndex) const;
  4486. UINT32 GetListIndex(UINT64 size) const;
  4487. void RemoveFreeBlock(Block* block);
  4488. void InsertFreeBlock(Block* block);
  4489. void MergeBlock(Block* block, Block* prev);
  4490. Block* FindFreeBlock(UINT64 size, UINT32& listIndex) const;
  4491. bool CheckBlock(
  4492. Block& block,
  4493. UINT32 listIndex,
  4494. UINT64 allocSize,
  4495. UINT64 allocAlignment,
  4496. AllocationRequest* pAllocationRequest);
  4497. D3D12MA_CLASS_NO_COPY(BlockMetadata_TLSF)
  4498. };
  4499. #ifndef _D3D12MA_BLOCK_METADATA_TLSF_FUNCTIONS
  4500. BlockMetadata_TLSF::BlockMetadata_TLSF(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual)
  4501. : BlockMetadata(allocationCallbacks, isVirtual),
  4502. m_BlockAllocator(*allocationCallbacks, INITIAL_BLOCK_ALLOC_COUNT)
  4503. {
  4504. D3D12MA_ASSERT(allocationCallbacks);
  4505. }
  4506. BlockMetadata_TLSF::~BlockMetadata_TLSF()
  4507. {
  4508. D3D12MA_DELETE_ARRAY(*GetAllocs(), m_FreeList, m_ListsCount);
  4509. }
  4510. void BlockMetadata_TLSF::Init(UINT64 size)
  4511. {
  4512. BlockMetadata::Init(size);
  4513. m_NullBlock = m_BlockAllocator.Alloc();
  4514. m_NullBlock->size = size;
  4515. m_NullBlock->offset = 0;
  4516. m_NullBlock->prevPhysical = NULL;
  4517. m_NullBlock->nextPhysical = NULL;
  4518. m_NullBlock->MarkFree();
  4519. m_NullBlock->NextFree() = NULL;
  4520. m_NullBlock->PrevFree() = NULL;
  4521. UINT8 memoryClass = SizeToMemoryClass(size);
  4522. UINT16 sli = SizeToSecondIndex(size, memoryClass);
  4523. m_ListsCount = (memoryClass == 0 ? 0 : (memoryClass - 1) * (1UL << SECOND_LEVEL_INDEX) + sli) + 1;
  4524. if (IsVirtual())
  4525. m_ListsCount += 1UL << SECOND_LEVEL_INDEX;
  4526. else
  4527. m_ListsCount += 4;
  4528. m_MemoryClasses = memoryClass + 2;
  4529. memset(m_InnerIsFreeBitmap, 0, MAX_MEMORY_CLASSES * sizeof(UINT32));
  4530. m_FreeList = D3D12MA_NEW_ARRAY(*GetAllocs(), Block*, m_ListsCount);
  4531. memset(m_FreeList, 0, m_ListsCount * sizeof(Block*));
  4532. }
  4533. bool BlockMetadata_TLSF::Validate() const
  4534. {
  4535. D3D12MA_VALIDATE(GetSumFreeSize() <= GetSize());
  4536. UINT64 calculatedSize = m_NullBlock->size;
  4537. UINT64 calculatedFreeSize = m_NullBlock->size;
  4538. size_t allocCount = 0;
  4539. size_t freeCount = 0;
  4540. // Check integrity of free lists
  4541. for (UINT32 list = 0; list < m_ListsCount; ++list)
  4542. {
  4543. Block* block = m_FreeList[list];
  4544. if (block != NULL)
  4545. {
  4546. D3D12MA_VALIDATE(block->IsFree());
  4547. D3D12MA_VALIDATE(block->PrevFree() == NULL);
  4548. while (block->NextFree())
  4549. {
  4550. D3D12MA_VALIDATE(block->NextFree()->IsFree());
  4551. D3D12MA_VALIDATE(block->NextFree()->PrevFree() == block);
  4552. block = block->NextFree();
  4553. }
  4554. }
  4555. }
  4556. D3D12MA_VALIDATE(m_NullBlock->nextPhysical == NULL);
  4557. if (m_NullBlock->prevPhysical)
  4558. {
  4559. D3D12MA_VALIDATE(m_NullBlock->prevPhysical->nextPhysical == m_NullBlock);
  4560. }
  4561. // Check all blocks
  4562. UINT64 nextOffset = m_NullBlock->offset;
  4563. for (Block* prev = m_NullBlock->prevPhysical; prev != NULL; prev = prev->prevPhysical)
  4564. {
  4565. D3D12MA_VALIDATE(prev->offset + prev->size == nextOffset);
  4566. nextOffset = prev->offset;
  4567. calculatedSize += prev->size;
  4568. UINT32 listIndex = GetListIndex(prev->size);
  4569. if (prev->IsFree())
  4570. {
  4571. ++freeCount;
  4572. // Check if free block belongs to free list
  4573. Block* freeBlock = m_FreeList[listIndex];
  4574. D3D12MA_VALIDATE(freeBlock != NULL);
  4575. bool found = false;
  4576. do
  4577. {
  4578. if (freeBlock == prev)
  4579. found = true;
  4580. freeBlock = freeBlock->NextFree();
  4581. } while (!found && freeBlock != NULL);
  4582. D3D12MA_VALIDATE(found);
  4583. calculatedFreeSize += prev->size;
  4584. }
  4585. else
  4586. {
  4587. ++allocCount;
  4588. // Check if taken block is not on a free list
  4589. Block* freeBlock = m_FreeList[listIndex];
  4590. while (freeBlock)
  4591. {
  4592. D3D12MA_VALIDATE(freeBlock != prev);
  4593. freeBlock = freeBlock->NextFree();
  4594. }
  4595. }
  4596. if (prev->prevPhysical)
  4597. {
  4598. D3D12MA_VALIDATE(prev->prevPhysical->nextPhysical == prev);
  4599. }
  4600. }
  4601. D3D12MA_VALIDATE(nextOffset == 0);
  4602. D3D12MA_VALIDATE(calculatedSize == GetSize());
  4603. D3D12MA_VALIDATE(calculatedFreeSize == GetSumFreeSize());
  4604. D3D12MA_VALIDATE(allocCount == m_AllocCount);
  4605. D3D12MA_VALIDATE(freeCount == m_BlocksFreeCount);
  4606. return true;
  4607. }
  4608. void BlockMetadata_TLSF::GetAllocationInfo(AllocHandle allocHandle, VIRTUAL_ALLOCATION_INFO& outInfo) const
  4609. {
  4610. Block* block = (Block*)allocHandle;
  4611. D3D12MA_ASSERT(!block->IsFree() && "Cannot get allocation info for free block!");
  4612. outInfo.Offset = block->offset;
  4613. outInfo.Size = block->size;
  4614. outInfo.pPrivateData = block->PrivateData();
  4615. }
  4616. bool BlockMetadata_TLSF::CreateAllocationRequest(
  4617. UINT64 allocSize,
  4618. UINT64 allocAlignment,
  4619. bool upperAddress,
  4620. UINT32 strategy,
  4621. AllocationRequest* pAllocationRequest)
  4622. {
  4623. D3D12MA_ASSERT(allocSize > 0 && "Cannot allocate empty block!");
  4624. D3D12MA_ASSERT(!upperAddress && "ALLOCATION_FLAG_UPPER_ADDRESS can be used only with linear algorithm.");
  4625. D3D12MA_ASSERT(pAllocationRequest != NULL);
  4626. D3D12MA_HEAVY_ASSERT(Validate());
  4627. allocSize += GetDebugMargin();
  4628. // Quick check for too small pool
  4629. if (allocSize > GetSumFreeSize())
  4630. return false;
  4631. // If no free blocks in pool then check only null block
  4632. if (m_BlocksFreeCount == 0)
  4633. return CheckBlock(*m_NullBlock, m_ListsCount, allocSize, allocAlignment, pAllocationRequest);
  4634. // Round up to the next block
  4635. UINT64 sizeForNextList = allocSize;
  4636. UINT16 smallSizeStep = SMALL_BUFFER_SIZE / (IsVirtual() ? 1 << SECOND_LEVEL_INDEX : 4);
  4637. if (allocSize > SMALL_BUFFER_SIZE)
  4638. {
  4639. sizeForNextList += (1ULL << (BitScanMSB(allocSize) - SECOND_LEVEL_INDEX));
  4640. }
  4641. else if (allocSize > SMALL_BUFFER_SIZE - smallSizeStep)
  4642. sizeForNextList = SMALL_BUFFER_SIZE + 1;
  4643. else
  4644. sizeForNextList += smallSizeStep;
  4645. UINT32 nextListIndex = 0;
  4646. UINT32 prevListIndex = 0;
  4647. Block* nextListBlock = NULL;
  4648. Block* prevListBlock = NULL;
  4649. // Check blocks according to strategies
  4650. if (strategy & ALLOCATION_FLAG_STRATEGY_MIN_TIME)
  4651. {
  4652. // Quick check for larger block first
  4653. nextListBlock = FindFreeBlock(sizeForNextList, nextListIndex);
  4654. if (nextListBlock != NULL && CheckBlock(*nextListBlock, nextListIndex, allocSize, allocAlignment, pAllocationRequest))
  4655. return true;
  4656. // If not fitted then null block
  4657. if (CheckBlock(*m_NullBlock, m_ListsCount, allocSize, allocAlignment, pAllocationRequest))
  4658. return true;
  4659. // Null block failed, search larger bucket
  4660. while (nextListBlock)
  4661. {
  4662. if (CheckBlock(*nextListBlock, nextListIndex, allocSize, allocAlignment, pAllocationRequest))
  4663. return true;
  4664. nextListBlock = nextListBlock->NextFree();
  4665. }
  4666. // Failed again, check best fit bucket
  4667. prevListBlock = FindFreeBlock(allocSize, prevListIndex);
  4668. while (prevListBlock)
  4669. {
  4670. if (CheckBlock(*prevListBlock, prevListIndex, allocSize, allocAlignment, pAllocationRequest))
  4671. return true;
  4672. prevListBlock = prevListBlock->NextFree();
  4673. }
  4674. }
  4675. else if (strategy & ALLOCATION_FLAG_STRATEGY_MIN_MEMORY)
  4676. {
  4677. // Check best fit bucket
  4678. prevListBlock = FindFreeBlock(allocSize, prevListIndex);
  4679. while (prevListBlock)
  4680. {
  4681. if (CheckBlock(*prevListBlock, prevListIndex, allocSize, allocAlignment, pAllocationRequest))
  4682. return true;
  4683. prevListBlock = prevListBlock->NextFree();
  4684. }
  4685. // If failed check null block
  4686. if (CheckBlock(*m_NullBlock, m_ListsCount, allocSize, allocAlignment, pAllocationRequest))
  4687. return true;
  4688. // Check larger bucket
  4689. nextListBlock = FindFreeBlock(sizeForNextList, nextListIndex);
  4690. while (nextListBlock)
  4691. {
  4692. if (CheckBlock(*nextListBlock, nextListIndex, allocSize, allocAlignment, pAllocationRequest))
  4693. return true;
  4694. nextListBlock = nextListBlock->NextFree();
  4695. }
  4696. }
  4697. else if (strategy & ALLOCATION_FLAG_STRATEGY_MIN_OFFSET)
  4698. {
  4699. // Perform search from the start
  4700. Vector<Block*> blockList(m_BlocksFreeCount, *GetAllocs());
  4701. size_t i = m_BlocksFreeCount;
  4702. for (Block* block = m_NullBlock->prevPhysical; block != NULL; block = block->prevPhysical)
  4703. {
  4704. if (block->IsFree() && block->size >= allocSize)
  4705. blockList[--i] = block;
  4706. }
  4707. for (; i < m_BlocksFreeCount; ++i)
  4708. {
  4709. Block& block = *blockList[i];
  4710. if (CheckBlock(block, GetListIndex(block.size), allocSize, allocAlignment, pAllocationRequest))
  4711. return true;
  4712. }
  4713. // If failed check null block
  4714. if (CheckBlock(*m_NullBlock, m_ListsCount, allocSize, allocAlignment, pAllocationRequest))
  4715. return true;
  4716. // Whole range searched, no more memory
  4717. return false;
  4718. }
  4719. else
  4720. {
  4721. // Check larger bucket
  4722. nextListBlock = FindFreeBlock(sizeForNextList, nextListIndex);
  4723. while (nextListBlock)
  4724. {
  4725. if (CheckBlock(*nextListBlock, nextListIndex, allocSize, allocAlignment, pAllocationRequest))
  4726. return true;
  4727. nextListBlock = nextListBlock->NextFree();
  4728. }
  4729. // If failed check null block
  4730. if (CheckBlock(*m_NullBlock, m_ListsCount, allocSize, allocAlignment, pAllocationRequest))
  4731. return true;
  4732. // Check best fit bucket
  4733. prevListBlock = FindFreeBlock(allocSize, prevListIndex);
  4734. while (prevListBlock)
  4735. {
  4736. if (CheckBlock(*prevListBlock, prevListIndex, allocSize, allocAlignment, pAllocationRequest))
  4737. return true;
  4738. prevListBlock = prevListBlock->NextFree();
  4739. }
  4740. }
  4741. // Worst case, full search has to be done
  4742. while (++nextListIndex < m_ListsCount)
  4743. {
  4744. nextListBlock = m_FreeList[nextListIndex];
  4745. while (nextListBlock)
  4746. {
  4747. if (CheckBlock(*nextListBlock, nextListIndex, allocSize, allocAlignment, pAllocationRequest))
  4748. return true;
  4749. nextListBlock = nextListBlock->NextFree();
  4750. }
  4751. }
  4752. // No more memory sadly
  4753. return false;
  4754. }
  4755. void BlockMetadata_TLSF::Alloc(
  4756. const AllocationRequest& request,
  4757. UINT64 allocSize,
  4758. void* privateData)
  4759. {
  4760. // Get block and pop it from the free list
  4761. Block* currentBlock = (Block*)request.allocHandle;
  4762. UINT64 offset = request.algorithmData;
  4763. D3D12MA_ASSERT(currentBlock != NULL);
  4764. D3D12MA_ASSERT(currentBlock->offset <= offset);
  4765. if (currentBlock != m_NullBlock)
  4766. RemoveFreeBlock(currentBlock);
  4767. // Append missing alignment to prev block or create new one
  4768. UINT64 misssingAlignment = offset - currentBlock->offset;
  4769. if (misssingAlignment)
  4770. {
  4771. Block* prevBlock = currentBlock->prevPhysical;
  4772. D3D12MA_ASSERT(prevBlock != NULL && "There should be no missing alignment at offset 0!");
  4773. if (prevBlock->IsFree() && prevBlock->size != GetDebugMargin())
  4774. {
  4775. UINT32 oldList = GetListIndex(prevBlock->size);
  4776. prevBlock->size += misssingAlignment;
  4777. // Check if new size crosses list bucket
  4778. if (oldList != GetListIndex(prevBlock->size))
  4779. {
  4780. prevBlock->size -= misssingAlignment;
  4781. RemoveFreeBlock(prevBlock);
  4782. prevBlock->size += misssingAlignment;
  4783. InsertFreeBlock(prevBlock);
  4784. }
  4785. else
  4786. m_BlocksFreeSize += misssingAlignment;
  4787. }
  4788. else
  4789. {
  4790. Block* newBlock = m_BlockAllocator.Alloc();
  4791. currentBlock->prevPhysical = newBlock;
  4792. prevBlock->nextPhysical = newBlock;
  4793. newBlock->prevPhysical = prevBlock;
  4794. newBlock->nextPhysical = currentBlock;
  4795. newBlock->size = misssingAlignment;
  4796. newBlock->offset = currentBlock->offset;
  4797. newBlock->MarkTaken();
  4798. InsertFreeBlock(newBlock);
  4799. }
  4800. currentBlock->size -= misssingAlignment;
  4801. currentBlock->offset += misssingAlignment;
  4802. }
  4803. UINT64 size = request.size + GetDebugMargin();
  4804. if (currentBlock->size == size)
  4805. {
  4806. if (currentBlock == m_NullBlock)
  4807. {
  4808. // Setup new null block
  4809. m_NullBlock = m_BlockAllocator.Alloc();
  4810. m_NullBlock->size = 0;
  4811. m_NullBlock->offset = currentBlock->offset + size;
  4812. m_NullBlock->prevPhysical = currentBlock;
  4813. m_NullBlock->nextPhysical = NULL;
  4814. m_NullBlock->MarkFree();
  4815. m_NullBlock->PrevFree() = NULL;
  4816. m_NullBlock->NextFree() = NULL;
  4817. currentBlock->nextPhysical = m_NullBlock;
  4818. currentBlock->MarkTaken();
  4819. }
  4820. }
  4821. else
  4822. {
  4823. D3D12MA_ASSERT(currentBlock->size > size && "Proper block already found, shouldn't find smaller one!");
  4824. // Create new free block
  4825. Block* newBlock = m_BlockAllocator.Alloc();
  4826. newBlock->size = currentBlock->size - size;
  4827. newBlock->offset = currentBlock->offset + size;
  4828. newBlock->prevPhysical = currentBlock;
  4829. newBlock->nextPhysical = currentBlock->nextPhysical;
  4830. currentBlock->nextPhysical = newBlock;
  4831. currentBlock->size = size;
  4832. if (currentBlock == m_NullBlock)
  4833. {
  4834. m_NullBlock = newBlock;
  4835. m_NullBlock->MarkFree();
  4836. m_NullBlock->NextFree() = NULL;
  4837. m_NullBlock->PrevFree() = NULL;
  4838. currentBlock->MarkTaken();
  4839. }
  4840. else
  4841. {
  4842. newBlock->nextPhysical->prevPhysical = newBlock;
  4843. newBlock->MarkTaken();
  4844. InsertFreeBlock(newBlock);
  4845. }
  4846. }
  4847. currentBlock->PrivateData() = privateData;
  4848. if (GetDebugMargin() > 0)
  4849. {
  4850. currentBlock->size -= GetDebugMargin();
  4851. Block* newBlock = m_BlockAllocator.Alloc();
  4852. newBlock->size = GetDebugMargin();
  4853. newBlock->offset = currentBlock->offset + currentBlock->size;
  4854. newBlock->prevPhysical = currentBlock;
  4855. newBlock->nextPhysical = currentBlock->nextPhysical;
  4856. newBlock->MarkTaken();
  4857. currentBlock->nextPhysical->prevPhysical = newBlock;
  4858. currentBlock->nextPhysical = newBlock;
  4859. InsertFreeBlock(newBlock);
  4860. }
  4861. ++m_AllocCount;
  4862. }
  4863. void BlockMetadata_TLSF::Free(AllocHandle allocHandle)
  4864. {
  4865. Block* block = (Block*)allocHandle;
  4866. Block* next = block->nextPhysical;
  4867. D3D12MA_ASSERT(!block->IsFree() && "Block is already free!");
  4868. --m_AllocCount;
  4869. if (GetDebugMargin() > 0)
  4870. {
  4871. RemoveFreeBlock(next);
  4872. MergeBlock(next, block);
  4873. block = next;
  4874. next = next->nextPhysical;
  4875. }
  4876. // Try merging
  4877. Block* prev = block->prevPhysical;
  4878. if (prev != NULL && prev->IsFree() && prev->size != GetDebugMargin())
  4879. {
  4880. RemoveFreeBlock(prev);
  4881. MergeBlock(block, prev);
  4882. }
  4883. if (!next->IsFree())
  4884. InsertFreeBlock(block);
  4885. else if (next == m_NullBlock)
  4886. MergeBlock(m_NullBlock, block);
  4887. else
  4888. {
  4889. RemoveFreeBlock(next);
  4890. MergeBlock(next, block);
  4891. InsertFreeBlock(next);
  4892. }
  4893. }
  4894. void BlockMetadata_TLSF::Clear()
  4895. {
  4896. m_AllocCount = 0;
  4897. m_BlocksFreeCount = 0;
  4898. m_BlocksFreeSize = 0;
  4899. m_IsFreeBitmap = 0;
  4900. m_NullBlock->offset = 0;
  4901. m_NullBlock->size = GetSize();
  4902. Block* block = m_NullBlock->prevPhysical;
  4903. m_NullBlock->prevPhysical = NULL;
  4904. while (block)
  4905. {
  4906. Block* prev = block->prevPhysical;
  4907. m_BlockAllocator.Free(block);
  4908. block = prev;
  4909. }
  4910. memset(m_FreeList, 0, m_ListsCount * sizeof(Block*));
  4911. memset(m_InnerIsFreeBitmap, 0, m_MemoryClasses * sizeof(UINT32));
  4912. }
  4913. AllocHandle BlockMetadata_TLSF::GetAllocationListBegin() const
  4914. {
  4915. if (m_AllocCount == 0)
  4916. return (AllocHandle)0;
  4917. for (Block* block = m_NullBlock->prevPhysical; block; block = block->prevPhysical)
  4918. {
  4919. if (!block->IsFree())
  4920. return (AllocHandle)block;
  4921. }
  4922. D3D12MA_ASSERT(false && "If m_AllocCount > 0 then should find any allocation!");
  4923. return (AllocHandle)0;
  4924. }
  4925. AllocHandle BlockMetadata_TLSF::GetNextAllocation(AllocHandle prevAlloc) const
  4926. {
  4927. Block* startBlock = (Block*)prevAlloc;
  4928. D3D12MA_ASSERT(!startBlock->IsFree() && "Incorrect block!");
  4929. for (Block* block = startBlock->prevPhysical; block; block = block->prevPhysical)
  4930. {
  4931. if (!block->IsFree())
  4932. return (AllocHandle)block;
  4933. }
  4934. return (AllocHandle)0;
  4935. }
  4936. UINT64 BlockMetadata_TLSF::GetNextFreeRegionSize(AllocHandle alloc) const
  4937. {
  4938. Block* block = (Block*)alloc;
  4939. D3D12MA_ASSERT(!block->IsFree() && "Incorrect block!");
  4940. if (block->prevPhysical)
  4941. return block->prevPhysical->IsFree() ? block->prevPhysical->size : 0;
  4942. return 0;
  4943. }
  4944. void* BlockMetadata_TLSF::GetAllocationPrivateData(AllocHandle allocHandle) const
  4945. {
  4946. Block* block = (Block*)allocHandle;
  4947. D3D12MA_ASSERT(!block->IsFree() && "Cannot get user data for free block!");
  4948. return block->PrivateData();
  4949. }
  4950. void BlockMetadata_TLSF::SetAllocationPrivateData(AllocHandle allocHandle, void* privateData)
  4951. {
  4952. Block* block = (Block*)allocHandle;
  4953. D3D12MA_ASSERT(!block->IsFree() && "Trying to set user data for not allocated block!");
  4954. block->PrivateData() = privateData;
  4955. }
  4956. void BlockMetadata_TLSF::AddStatistics(Statistics& inoutStats) const
  4957. {
  4958. inoutStats.BlockCount++;
  4959. inoutStats.AllocationCount += static_cast<UINT>(m_AllocCount);
  4960. inoutStats.BlockBytes += GetSize();
  4961. inoutStats.AllocationBytes += GetSize() - GetSumFreeSize();
  4962. }
  4963. void BlockMetadata_TLSF::AddDetailedStatistics(DetailedStatistics& inoutStats) const
  4964. {
  4965. inoutStats.Stats.BlockCount++;
  4966. inoutStats.Stats.BlockBytes += GetSize();
  4967. for (Block* block = m_NullBlock->prevPhysical; block != NULL; block = block->prevPhysical)
  4968. {
  4969. if (block->IsFree())
  4970. AddDetailedStatisticsUnusedRange(inoutStats, block->size);
  4971. else
  4972. AddDetailedStatisticsAllocation(inoutStats, block->size);
  4973. }
  4974. if (m_NullBlock->size > 0)
  4975. AddDetailedStatisticsUnusedRange(inoutStats, m_NullBlock->size);
  4976. }
  4977. void BlockMetadata_TLSF::WriteAllocationInfoToJson(JsonWriter& json) const
  4978. {
  4979. size_t blockCount = m_AllocCount + m_BlocksFreeCount;
  4980. Vector<Block*> blockList(blockCount, *GetAllocs());
  4981. size_t i = blockCount;
  4982. if (m_NullBlock->size > 0)
  4983. {
  4984. ++blockCount;
  4985. blockList.push_back(m_NullBlock);
  4986. }
  4987. for (Block* block = m_NullBlock->prevPhysical; block != NULL; block = block->prevPhysical)
  4988. {
  4989. blockList[--i] = block;
  4990. }
  4991. D3D12MA_ASSERT(i == 0);
  4992. PrintDetailedMap_Begin(json, GetSumFreeSize(), GetAllocationCount(), m_BlocksFreeCount + static_cast<bool>(m_NullBlock->size));
  4993. for (; i < blockCount; ++i)
  4994. {
  4995. Block* block = blockList[i];
  4996. if (block->IsFree())
  4997. PrintDetailedMap_UnusedRange(json, block->offset, block->size);
  4998. else
  4999. PrintDetailedMap_Allocation(json, block->offset, block->size, block->PrivateData());
  5000. }
  5001. PrintDetailedMap_End(json);
  5002. }
  5003. void BlockMetadata_TLSF::DebugLogAllAllocations() const
  5004. {
  5005. for (Block* block = m_NullBlock->prevPhysical; block != NULL; block = block->prevPhysical)
  5006. {
  5007. if (!block->IsFree())
  5008. {
  5009. DebugLogAllocation(block->offset, block->size, block->PrivateData());
  5010. }
  5011. }
  5012. }
  5013. UINT8 BlockMetadata_TLSF::SizeToMemoryClass(UINT64 size) const
  5014. {
  5015. if (size > SMALL_BUFFER_SIZE)
  5016. return BitScanMSB(size) - MEMORY_CLASS_SHIFT;
  5017. return 0;
  5018. }
  5019. UINT16 BlockMetadata_TLSF::SizeToSecondIndex(UINT64 size, UINT8 memoryClass) const
  5020. {
  5021. if (memoryClass == 0)
  5022. {
  5023. if (IsVirtual())
  5024. return static_cast<UINT16>((size - 1) / 8);
  5025. else
  5026. return static_cast<UINT16>((size - 1) / 64);
  5027. }
  5028. return static_cast<UINT16>((size >> (memoryClass + MEMORY_CLASS_SHIFT - SECOND_LEVEL_INDEX)) ^ (1U << SECOND_LEVEL_INDEX));
  5029. }
  5030. UINT32 BlockMetadata_TLSF::GetListIndex(UINT8 memoryClass, UINT16 secondIndex) const
  5031. {
  5032. if (memoryClass == 0)
  5033. return secondIndex;
  5034. const UINT32 index = static_cast<UINT32>(memoryClass - 1) * (1 << SECOND_LEVEL_INDEX) + secondIndex;
  5035. if (IsVirtual())
  5036. return index + (1 << SECOND_LEVEL_INDEX);
  5037. else
  5038. return index + 4;
  5039. }
  5040. UINT32 BlockMetadata_TLSF::GetListIndex(UINT64 size) const
  5041. {
  5042. UINT8 memoryClass = SizeToMemoryClass(size);
  5043. return GetListIndex(memoryClass, SizeToSecondIndex(size, memoryClass));
  5044. }
  5045. void BlockMetadata_TLSF::RemoveFreeBlock(Block* block)
  5046. {
  5047. D3D12MA_ASSERT(block != m_NullBlock);
  5048. D3D12MA_ASSERT(block->IsFree());
  5049. if (block->NextFree() != NULL)
  5050. block->NextFree()->PrevFree() = block->PrevFree();
  5051. if (block->PrevFree() != NULL)
  5052. block->PrevFree()->NextFree() = block->NextFree();
  5053. else
  5054. {
  5055. UINT8 memClass = SizeToMemoryClass(block->size);
  5056. UINT16 secondIndex = SizeToSecondIndex(block->size, memClass);
  5057. UINT32 index = GetListIndex(memClass, secondIndex);
  5058. m_FreeList[index] = block->NextFree();
  5059. if (block->NextFree() == NULL)
  5060. {
  5061. m_InnerIsFreeBitmap[memClass] &= ~(1U << secondIndex);
  5062. if (m_InnerIsFreeBitmap[memClass] == 0)
  5063. m_IsFreeBitmap &= ~(1UL << memClass);
  5064. }
  5065. }
  5066. block->MarkTaken();
  5067. block->PrivateData() = NULL;
  5068. --m_BlocksFreeCount;
  5069. m_BlocksFreeSize -= block->size;
  5070. }
  5071. void BlockMetadata_TLSF::InsertFreeBlock(Block* block)
  5072. {
  5073. D3D12MA_ASSERT(block != m_NullBlock);
  5074. D3D12MA_ASSERT(!block->IsFree() && "Cannot insert block twice!");
  5075. UINT8 memClass = SizeToMemoryClass(block->size);
  5076. UINT16 secondIndex = SizeToSecondIndex(block->size, memClass);
  5077. UINT32 index = GetListIndex(memClass, secondIndex);
  5078. block->PrevFree() = NULL;
  5079. block->NextFree() = m_FreeList[index];
  5080. m_FreeList[index] = block;
  5081. if (block->NextFree() != NULL)
  5082. block->NextFree()->PrevFree() = block;
  5083. else
  5084. {
  5085. m_InnerIsFreeBitmap[memClass] |= 1U << secondIndex;
  5086. m_IsFreeBitmap |= 1UL << memClass;
  5087. }
  5088. ++m_BlocksFreeCount;
  5089. m_BlocksFreeSize += block->size;
  5090. }
  5091. void BlockMetadata_TLSF::MergeBlock(Block* block, Block* prev)
  5092. {
  5093. D3D12MA_ASSERT(block->prevPhysical == prev && "Cannot merge seperate physical regions!");
  5094. D3D12MA_ASSERT(!prev->IsFree() && "Cannot merge block that belongs to free list!");
  5095. block->offset = prev->offset;
  5096. block->size += prev->size;
  5097. block->prevPhysical = prev->prevPhysical;
  5098. if (block->prevPhysical)
  5099. block->prevPhysical->nextPhysical = block;
  5100. m_BlockAllocator.Free(prev);
  5101. }
  5102. BlockMetadata_TLSF::Block* BlockMetadata_TLSF::FindFreeBlock(UINT64 size, UINT32& listIndex) const
  5103. {
  5104. UINT8 memoryClass = SizeToMemoryClass(size);
  5105. UINT32 innerFreeMap = m_InnerIsFreeBitmap[memoryClass] & (~0U << SizeToSecondIndex(size, memoryClass));
  5106. if (!innerFreeMap)
  5107. {
  5108. // Check higher levels for avaiable blocks
  5109. UINT32 freeMap = m_IsFreeBitmap & (~0UL << (memoryClass + 1));
  5110. if (!freeMap)
  5111. return NULL; // No more memory avaible
  5112. // Find lowest free region
  5113. memoryClass = BitScanLSB(freeMap);
  5114. innerFreeMap = m_InnerIsFreeBitmap[memoryClass];
  5115. D3D12MA_ASSERT(innerFreeMap != 0);
  5116. }
  5117. // Find lowest free subregion
  5118. listIndex = GetListIndex(memoryClass, BitScanLSB(innerFreeMap));
  5119. return m_FreeList[listIndex];
  5120. }
  5121. bool BlockMetadata_TLSF::CheckBlock(
  5122. Block& block,
  5123. UINT32 listIndex,
  5124. UINT64 allocSize,
  5125. UINT64 allocAlignment,
  5126. AllocationRequest* pAllocationRequest)
  5127. {
  5128. D3D12MA_ASSERT(block.IsFree() && "Block is already taken!");
  5129. UINT64 alignedOffset = AlignUp(block.offset, allocAlignment);
  5130. if (block.size < allocSize + alignedOffset - block.offset)
  5131. return false;
  5132. // Alloc successful
  5133. pAllocationRequest->allocHandle = (AllocHandle)&block;
  5134. pAllocationRequest->size = allocSize - GetDebugMargin();
  5135. pAllocationRequest->algorithmData = alignedOffset;
  5136. // Place block at the start of list if it's normal block
  5137. if (listIndex != m_ListsCount && block.PrevFree())
  5138. {
  5139. block.PrevFree()->NextFree() = block.NextFree();
  5140. if (block.NextFree())
  5141. block.NextFree()->PrevFree() = block.PrevFree();
  5142. block.PrevFree() = NULL;
  5143. block.NextFree() = m_FreeList[listIndex];
  5144. m_FreeList[listIndex] = &block;
  5145. if (block.NextFree())
  5146. block.NextFree()->PrevFree() = &block;
  5147. }
  5148. return true;
  5149. }
  5150. #endif // _D3D12MA_BLOCK_METADATA_TLSF_FUNCTIONS
  5151. #endif // _D3D12MA_BLOCK_METADATA_TLSF
  5152. #ifndef _D3D12MA_MEMORY_BLOCK
  5153. /*
  5154. Represents a single block of device memory (heap).
  5155. Base class for inheritance.
  5156. Thread-safety: This class must be externally synchronized.
  5157. */
  5158. class MemoryBlock
  5159. {
  5160. public:
  5161. // Creates the ID3D12Heap.
  5162. MemoryBlock(
  5163. AllocatorPimpl* allocator,
  5164. const D3D12_HEAP_PROPERTIES& heapProps,
  5165. D3D12_HEAP_FLAGS heapFlags,
  5166. UINT64 size,
  5167. UINT id);
  5168. virtual ~MemoryBlock();
  5169. const D3D12_HEAP_PROPERTIES& GetHeapProperties() const { return m_HeapProps; }
  5170. D3D12_HEAP_FLAGS GetHeapFlags() const { return m_HeapFlags; }
  5171. UINT64 GetSize() const { return m_Size; }
  5172. UINT GetId() const { return m_Id; }
  5173. ID3D12Heap* GetHeap() const { return m_Heap; }
  5174. protected:
  5175. AllocatorPimpl* const m_Allocator;
  5176. const D3D12_HEAP_PROPERTIES m_HeapProps;
  5177. const D3D12_HEAP_FLAGS m_HeapFlags;
  5178. const UINT64 m_Size;
  5179. const UINT m_Id;
  5180. HRESULT Init(ID3D12ProtectedResourceSession* pProtectedSession, bool denyMsaaTextures);
  5181. private:
  5182. ID3D12Heap* m_Heap = NULL;
  5183. D3D12MA_CLASS_NO_COPY(MemoryBlock)
  5184. };
  5185. #endif // _D3D12MA_MEMORY_BLOCK
  5186. #ifndef _D3D12MA_NORMAL_BLOCK
  5187. /*
  5188. Represents a single block of device memory (heap) with all the data about its
  5189. regions (aka suballocations, Allocation), assigned and free.
  5190. Thread-safety: This class must be externally synchronized.
  5191. */
  5192. class NormalBlock : public MemoryBlock
  5193. {
  5194. public:
  5195. BlockMetadata* m_pMetadata;
  5196. NormalBlock(
  5197. AllocatorPimpl* allocator,
  5198. BlockVector* blockVector,
  5199. const D3D12_HEAP_PROPERTIES& heapProps,
  5200. D3D12_HEAP_FLAGS heapFlags,
  5201. UINT64 size,
  5202. UINT id);
  5203. virtual ~NormalBlock();
  5204. BlockVector* GetBlockVector() const { return m_BlockVector; }
  5205. // 'algorithm' should be one of the *_ALGORITHM_* flags in enums POOL_FLAGS or VIRTUAL_BLOCK_FLAGS
  5206. HRESULT Init(UINT32 algorithm, ID3D12ProtectedResourceSession* pProtectedSession, bool denyMsaaTextures);
  5207. // Validates all data structures inside this object. If not valid, returns false.
  5208. bool Validate() const;
  5209. private:
  5210. BlockVector* m_BlockVector;
  5211. D3D12MA_CLASS_NO_COPY(NormalBlock)
  5212. };
  5213. #endif // _D3D12MA_NORMAL_BLOCK
  5214. #ifndef _D3D12MA_COMMITTED_ALLOCATION_LIST_ITEM_TRAITS
  5215. struct CommittedAllocationListItemTraits
  5216. {
  5217. using ItemType = Allocation;
  5218. static ItemType* GetPrev(const ItemType* item)
  5219. {
  5220. D3D12MA_ASSERT(item->m_PackedData.GetType() == Allocation::TYPE_COMMITTED || item->m_PackedData.GetType() == Allocation::TYPE_HEAP);
  5221. return item->m_Committed.prev;
  5222. }
  5223. static ItemType* GetNext(const ItemType* item)
  5224. {
  5225. D3D12MA_ASSERT(item->m_PackedData.GetType() == Allocation::TYPE_COMMITTED || item->m_PackedData.GetType() == Allocation::TYPE_HEAP);
  5226. return item->m_Committed.next;
  5227. }
  5228. static ItemType*& AccessPrev(ItemType* item)
  5229. {
  5230. D3D12MA_ASSERT(item->m_PackedData.GetType() == Allocation::TYPE_COMMITTED || item->m_PackedData.GetType() == Allocation::TYPE_HEAP);
  5231. return item->m_Committed.prev;
  5232. }
  5233. static ItemType*& AccessNext(ItemType* item)
  5234. {
  5235. D3D12MA_ASSERT(item->m_PackedData.GetType() == Allocation::TYPE_COMMITTED || item->m_PackedData.GetType() == Allocation::TYPE_HEAP);
  5236. return item->m_Committed.next;
  5237. }
  5238. };
  5239. #endif // _D3D12MA_COMMITTED_ALLOCATION_LIST_ITEM_TRAITS
  5240. #ifndef _D3D12MA_COMMITTED_ALLOCATION_LIST
  5241. /*
  5242. Stores linked list of Allocation objects that are of TYPE_COMMITTED or TYPE_HEAP.
  5243. Thread-safe, synchronized internally.
  5244. */
  5245. class CommittedAllocationList
  5246. {
  5247. public:
  5248. CommittedAllocationList() = default;
  5249. void Init(bool useMutex, D3D12_HEAP_TYPE heapType, PoolPimpl* pool);
  5250. ~CommittedAllocationList();
  5251. D3D12_HEAP_TYPE GetHeapType() const { return m_HeapType; }
  5252. PoolPimpl* GetPool() const { return m_Pool; }
  5253. UINT GetMemorySegmentGroup(AllocatorPimpl* allocator) const;
  5254. void AddStatistics(Statistics& inoutStats);
  5255. void AddDetailedStatistics(DetailedStatistics& inoutStats);
  5256. // Writes JSON array with the list of allocations.
  5257. void BuildStatsString(JsonWriter& json);
  5258. void Register(Allocation* alloc);
  5259. void Unregister(Allocation* alloc);
  5260. private:
  5261. using CommittedAllocationLinkedList = IntrusiveLinkedList<CommittedAllocationListItemTraits>;
  5262. bool m_UseMutex = true;
  5263. D3D12_HEAP_TYPE m_HeapType = D3D12_HEAP_TYPE_CUSTOM;
  5264. PoolPimpl* m_Pool = NULL;
  5265. D3D12MA_RW_MUTEX m_Mutex;
  5266. CommittedAllocationLinkedList m_AllocationList;
  5267. };
  5268. #endif // _D3D12MA_COMMITTED_ALLOCATION_LIST
  5269. #ifndef _D3D12M_COMMITTED_ALLOCATION_PARAMETERS
  5270. struct CommittedAllocationParameters
  5271. {
  5272. CommittedAllocationList* m_List = NULL;
  5273. D3D12_HEAP_PROPERTIES m_HeapProperties = {};
  5274. D3D12_HEAP_FLAGS m_HeapFlags = D3D12_HEAP_FLAG_NONE;
  5275. ID3D12ProtectedResourceSession* m_ProtectedSession = NULL;
  5276. bool m_CanAlias = false;
  5277. D3D12_RESIDENCY_PRIORITY m_ResidencyPriority = D3D12_RESIDENCY_PRIORITY_NONE;
  5278. bool IsValid() const { return m_List != NULL; }
  5279. };
  5280. #endif // _D3D12M_COMMITTED_ALLOCATION_PARAMETERS
  5281. // Simple variant data structure to hold all possible variations of ID3D12Device*::CreateCommittedResource* and ID3D12Device*::CreatePlacedResource* arguments
  5282. struct CREATE_RESOURCE_PARAMS
  5283. {
  5284. CREATE_RESOURCE_PARAMS() = delete;
  5285. CREATE_RESOURCE_PARAMS(
  5286. const D3D12_RESOURCE_DESC* pResourceDesc,
  5287. D3D12_RESOURCE_STATES InitialResourceState,
  5288. const D3D12_CLEAR_VALUE* pOptimizedClearValue)
  5289. : Variant(VARIANT_WITH_STATE)
  5290. , pResourceDesc(pResourceDesc)
  5291. , InitialResourceState(InitialResourceState)
  5292. , pOptimizedClearValue(pOptimizedClearValue)
  5293. {
  5294. }
  5295. #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  5296. CREATE_RESOURCE_PARAMS(
  5297. const D3D12_RESOURCE_DESC1* pResourceDesc,
  5298. D3D12_RESOURCE_STATES InitialResourceState,
  5299. const D3D12_CLEAR_VALUE* pOptimizedClearValue)
  5300. : Variant(VARIANT_WITH_STATE_AND_DESC1)
  5301. , pResourceDesc1(pResourceDesc)
  5302. , InitialResourceState(InitialResourceState)
  5303. , pOptimizedClearValue(pOptimizedClearValue)
  5304. {
  5305. }
  5306. #endif
  5307. #ifdef __ID3D12Device10_INTERFACE_DEFINED__
  5308. CREATE_RESOURCE_PARAMS(
  5309. const D3D12_RESOURCE_DESC1* pResourceDesc,
  5310. D3D12_BARRIER_LAYOUT InitialLayout,
  5311. const D3D12_CLEAR_VALUE* pOptimizedClearValue,
  5312. UINT32 NumCastableFormats,
  5313. DXGI_FORMAT* pCastableFormats)
  5314. : Variant(VARIANT_WITH_LAYOUT)
  5315. , pResourceDesc1(pResourceDesc)
  5316. , InitialLayout(InitialLayout)
  5317. , pOptimizedClearValue(pOptimizedClearValue)
  5318. , NumCastableFormats(NumCastableFormats)
  5319. , pCastableFormats(pCastableFormats)
  5320. {
  5321. }
  5322. #endif
  5323. enum VARIANT
  5324. {
  5325. VARIANT_INVALID = 0,
  5326. VARIANT_WITH_STATE,
  5327. VARIANT_WITH_STATE_AND_DESC1,
  5328. VARIANT_WITH_LAYOUT
  5329. };
  5330. VARIANT Variant = VARIANT_INVALID;
  5331. const D3D12_RESOURCE_DESC* GetResourceDesc() const
  5332. {
  5333. D3D12MA_ASSERT(Variant == VARIANT_WITH_STATE);
  5334. return pResourceDesc;
  5335. }
  5336. const D3D12_RESOURCE_DESC*& AccessResourceDesc()
  5337. {
  5338. D3D12MA_ASSERT(Variant == VARIANT_WITH_STATE);
  5339. return pResourceDesc;
  5340. }
  5341. const D3D12_RESOURCE_DESC* GetBaseResourceDesc() const
  5342. {
  5343. // D3D12_RESOURCE_DESC1 can be cast to D3D12_RESOURCE_DESC by discarding the new members at the end.
  5344. return pResourceDesc;
  5345. }
  5346. D3D12_RESOURCE_STATES GetInitialResourceState() const
  5347. {
  5348. D3D12MA_ASSERT(Variant < VARIANT_WITH_LAYOUT);
  5349. return InitialResourceState;
  5350. }
  5351. const D3D12_CLEAR_VALUE* GetOptimizedClearValue() const
  5352. {
  5353. return pOptimizedClearValue;
  5354. }
  5355. #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  5356. const D3D12_RESOURCE_DESC1* GetResourceDesc1() const
  5357. {
  5358. D3D12MA_ASSERT(Variant >= VARIANT_WITH_STATE_AND_DESC1);
  5359. return pResourceDesc1;
  5360. }
  5361. const D3D12_RESOURCE_DESC1*& AccessResourceDesc1()
  5362. {
  5363. D3D12MA_ASSERT(Variant >= VARIANT_WITH_STATE_AND_DESC1);
  5364. return pResourceDesc1;
  5365. }
  5366. #endif
  5367. #ifdef __ID3D12Device10_INTERFACE_DEFINED__
  5368. D3D12_BARRIER_LAYOUT GetInitialLayout() const
  5369. {
  5370. D3D12MA_ASSERT(Variant >= VARIANT_WITH_LAYOUT);
  5371. return InitialLayout;
  5372. }
  5373. UINT32 GetNumCastableFormats() const
  5374. {
  5375. D3D12MA_ASSERT(Variant >= VARIANT_WITH_LAYOUT);
  5376. return NumCastableFormats;
  5377. }
  5378. DXGI_FORMAT* GetCastableFormats() const
  5379. {
  5380. D3D12MA_ASSERT(Variant >= VARIANT_WITH_LAYOUT);
  5381. return pCastableFormats;
  5382. }
  5383. #endif
  5384. private:
  5385. union
  5386. {
  5387. const D3D12_RESOURCE_DESC* pResourceDesc;
  5388. #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  5389. const D3D12_RESOURCE_DESC1* pResourceDesc1;
  5390. #endif
  5391. };
  5392. union
  5393. {
  5394. D3D12_RESOURCE_STATES InitialResourceState;
  5395. #ifdef __ID3D12Device10_INTERFACE_DEFINED__
  5396. D3D12_BARRIER_LAYOUT InitialLayout;
  5397. #endif
  5398. };
  5399. const D3D12_CLEAR_VALUE* pOptimizedClearValue;
  5400. #ifdef __ID3D12Device10_INTERFACE_DEFINED__
  5401. UINT32 NumCastableFormats;
  5402. DXGI_FORMAT* pCastableFormats;
  5403. #endif
  5404. };
  5405. #ifndef _D3D12MA_BLOCK_VECTOR
  5406. /*
  5407. Sequence of NormalBlock. Represents memory blocks allocated for a specific
  5408. heap type and possibly resource type (if only Tier 1 is supported).
  5409. Synchronized internally with a mutex.
  5410. */
  5411. class BlockVector
  5412. {
  5413. friend class DefragmentationContextPimpl;
  5414. D3D12MA_CLASS_NO_COPY(BlockVector)
  5415. public:
  5416. BlockVector(
  5417. AllocatorPimpl* hAllocator,
  5418. const D3D12_HEAP_PROPERTIES& heapProps,
  5419. D3D12_HEAP_FLAGS heapFlags,
  5420. UINT64 preferredBlockSize,
  5421. size_t minBlockCount,
  5422. size_t maxBlockCount,
  5423. bool explicitBlockSize,
  5424. UINT64 minAllocationAlignment,
  5425. UINT32 algorithm,
  5426. bool denyMsaaTextures,
  5427. ID3D12ProtectedResourceSession* pProtectedSession,
  5428. D3D12_RESIDENCY_PRIORITY residencyPriority);
  5429. ~BlockVector();
  5430. D3D12_RESIDENCY_PRIORITY GetResidencyPriority() const { return m_ResidencyPriority; }
  5431. const D3D12_HEAP_PROPERTIES& GetHeapProperties() const { return m_HeapProps; }
  5432. D3D12_HEAP_FLAGS GetHeapFlags() const { return m_HeapFlags; }
  5433. UINT64 GetPreferredBlockSize() const { return m_PreferredBlockSize; }
  5434. UINT32 GetAlgorithm() const { return m_Algorithm; }
  5435. bool DeniesMsaaTextures() const { return m_DenyMsaaTextures; }
  5436. // To be used only while the m_Mutex is locked. Used during defragmentation.
  5437. size_t GetBlockCount() const { return m_Blocks.size(); }
  5438. // To be used only while the m_Mutex is locked. Used during defragmentation.
  5439. NormalBlock* GetBlock(size_t index) const { return m_Blocks[index]; }
  5440. D3D12MA_RW_MUTEX& GetMutex() { return m_Mutex; }
  5441. HRESULT CreateMinBlocks();
  5442. bool IsEmpty();
  5443. HRESULT Allocate(
  5444. UINT64 size,
  5445. UINT64 alignment,
  5446. const ALLOCATION_DESC& allocDesc,
  5447. size_t allocationCount,
  5448. Allocation** pAllocations);
  5449. void Free(Allocation* hAllocation);
  5450. HRESULT CreateResource(
  5451. UINT64 size,
  5452. UINT64 alignment,
  5453. const ALLOCATION_DESC& allocDesc,
  5454. const CREATE_RESOURCE_PARAMS& createParams,
  5455. Allocation** ppAllocation,
  5456. REFIID riidResource,
  5457. void** ppvResource);
  5458. void AddStatistics(Statistics& inoutStats);
  5459. void AddDetailedStatistics(DetailedStatistics& inoutStats);
  5460. void WriteBlockInfoToJson(JsonWriter& json);
  5461. private:
  5462. AllocatorPimpl* const m_hAllocator;
  5463. const D3D12_HEAP_PROPERTIES m_HeapProps;
  5464. const D3D12_HEAP_FLAGS m_HeapFlags;
  5465. const UINT64 m_PreferredBlockSize;
  5466. const size_t m_MinBlockCount;
  5467. const size_t m_MaxBlockCount;
  5468. const bool m_ExplicitBlockSize;
  5469. const UINT64 m_MinAllocationAlignment;
  5470. const UINT32 m_Algorithm;
  5471. const bool m_DenyMsaaTextures;
  5472. ID3D12ProtectedResourceSession* const m_ProtectedSession;
  5473. const D3D12_RESIDENCY_PRIORITY m_ResidencyPriority;
  5474. /* There can be at most one allocation that is completely empty - a
  5475. hysteresis to avoid pessimistic case of alternating creation and destruction
  5476. of a ID3D12Heap. */
  5477. bool m_HasEmptyBlock;
  5478. D3D12MA_RW_MUTEX m_Mutex;
  5479. // Incrementally sorted by sumFreeSize, ascending.
  5480. Vector<NormalBlock*> m_Blocks;
  5481. UINT m_NextBlockId;
  5482. bool m_IncrementalSort = true;
  5483. // Disable incremental sorting when freeing allocations
  5484. void SetIncrementalSort(bool val) { m_IncrementalSort = val; }
  5485. UINT64 CalcSumBlockSize() const;
  5486. UINT64 CalcMaxBlockSize() const;
  5487. // Finds and removes given block from vector.
  5488. void Remove(NormalBlock* pBlock);
  5489. // Performs single step in sorting m_Blocks. They may not be fully sorted
  5490. // after this call.
  5491. void IncrementallySortBlocks();
  5492. void SortByFreeSize();
  5493. HRESULT AllocatePage(
  5494. UINT64 size,
  5495. UINT64 alignment,
  5496. const ALLOCATION_DESC& allocDesc,
  5497. Allocation** pAllocation);
  5498. HRESULT AllocateFromBlock(
  5499. NormalBlock* pBlock,
  5500. UINT64 size,
  5501. UINT64 alignment,
  5502. ALLOCATION_FLAGS allocFlags,
  5503. void* pPrivateData,
  5504. UINT32 strategy,
  5505. Allocation** pAllocation);
  5506. HRESULT CommitAllocationRequest(
  5507. AllocationRequest& allocRequest,
  5508. NormalBlock* pBlock,
  5509. UINT64 size,
  5510. UINT64 alignment,
  5511. void* pPrivateData,
  5512. Allocation** pAllocation);
  5513. HRESULT CreateBlock(
  5514. UINT64 blockSize,
  5515. size_t* pNewBlockIndex);
  5516. };
  5517. #endif // _D3D12MA_BLOCK_VECTOR
  5518. #ifndef _D3D12MA_CURRENT_BUDGET_DATA
  5519. class CurrentBudgetData
  5520. {
  5521. public:
  5522. bool ShouldUpdateBudget() const { return m_OperationsSinceBudgetFetch >= 30; }
  5523. void GetStatistics(Statistics& outStats, UINT group) const;
  5524. void GetBudget(bool useMutex,
  5525. UINT64* outLocalUsage, UINT64* outLocalBudget,
  5526. UINT64* outNonLocalUsage, UINT64* outNonLocalBudget);
  5527. #if D3D12MA_DXGI_1_4
  5528. HRESULT UpdateBudget(IDXGIAdapter3* adapter3, bool useMutex);
  5529. #endif
  5530. void AddAllocation(UINT group, UINT64 allocationBytes);
  5531. void RemoveAllocation(UINT group, UINT64 allocationBytes);
  5532. void AddBlock(UINT group, UINT64 blockBytes);
  5533. void RemoveBlock(UINT group, UINT64 blockBytes);
  5534. private:
  5535. D3D12MA_ATOMIC_UINT32 m_BlockCount[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
  5536. D3D12MA_ATOMIC_UINT32 m_AllocationCount[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
  5537. D3D12MA_ATOMIC_UINT64 m_BlockBytes[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
  5538. D3D12MA_ATOMIC_UINT64 m_AllocationBytes[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
  5539. D3D12MA_ATOMIC_UINT32 m_OperationsSinceBudgetFetch = {0};
  5540. D3D12MA_RW_MUTEX m_BudgetMutex;
  5541. UINT64 m_D3D12Usage[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
  5542. UINT64 m_D3D12Budget[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
  5543. UINT64 m_BlockBytesAtD3D12Fetch[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
  5544. };
  5545. #ifndef _D3D12MA_CURRENT_BUDGET_DATA_FUNCTIONS
  5546. void CurrentBudgetData::GetStatistics(Statistics& outStats, UINT group) const
  5547. {
  5548. outStats.BlockCount = m_BlockCount[group];
  5549. outStats.AllocationCount = m_AllocationCount[group];
  5550. outStats.BlockBytes = m_BlockBytes[group];
  5551. outStats.AllocationBytes = m_AllocationBytes[group];
  5552. }
  5553. void CurrentBudgetData::GetBudget(bool useMutex,
  5554. UINT64* outLocalUsage, UINT64* outLocalBudget,
  5555. UINT64* outNonLocalUsage, UINT64* outNonLocalBudget)
  5556. {
  5557. MutexLockRead lockRead(m_BudgetMutex, useMutex);
  5558. if (outLocalUsage)
  5559. {
  5560. const UINT64 D3D12Usage = m_D3D12Usage[DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY];
  5561. const UINT64 blockBytes = m_BlockBytes[DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY];
  5562. const UINT64 blockBytesAtD3D12Fetch = m_BlockBytesAtD3D12Fetch[DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY];
  5563. *outLocalUsage = D3D12Usage + blockBytes > blockBytesAtD3D12Fetch ?
  5564. D3D12Usage + blockBytes - blockBytesAtD3D12Fetch : 0;
  5565. }
  5566. if (outLocalBudget)
  5567. *outLocalBudget = m_D3D12Budget[DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY];
  5568. if (outNonLocalUsage)
  5569. {
  5570. const UINT64 D3D12Usage = m_D3D12Usage[DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY];
  5571. const UINT64 blockBytes = m_BlockBytes[DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY];
  5572. const UINT64 blockBytesAtD3D12Fetch = m_BlockBytesAtD3D12Fetch[DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY];
  5573. *outNonLocalUsage = D3D12Usage + blockBytes > blockBytesAtD3D12Fetch ?
  5574. D3D12Usage + blockBytes - blockBytesAtD3D12Fetch : 0;
  5575. }
  5576. if (outNonLocalBudget)
  5577. *outNonLocalBudget = m_D3D12Budget[DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY];
  5578. }
  5579. #if D3D12MA_DXGI_1_4
  5580. HRESULT CurrentBudgetData::UpdateBudget(IDXGIAdapter3* adapter3, bool useMutex)
  5581. {
  5582. D3D12MA_ASSERT(adapter3);
  5583. DXGI_QUERY_VIDEO_MEMORY_INFO infoLocal = {};
  5584. DXGI_QUERY_VIDEO_MEMORY_INFO infoNonLocal = {};
  5585. const HRESULT hrLocal = adapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &infoLocal);
  5586. const HRESULT hrNonLocal = adapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &infoNonLocal);
  5587. if (SUCCEEDED(hrLocal) || SUCCEEDED(hrNonLocal))
  5588. {
  5589. MutexLockWrite lockWrite(m_BudgetMutex, useMutex);
  5590. if (SUCCEEDED(hrLocal))
  5591. {
  5592. m_D3D12Usage[0] = infoLocal.CurrentUsage;
  5593. m_D3D12Budget[0] = infoLocal.Budget;
  5594. }
  5595. if (SUCCEEDED(hrNonLocal))
  5596. {
  5597. m_D3D12Usage[1] = infoNonLocal.CurrentUsage;
  5598. m_D3D12Budget[1] = infoNonLocal.Budget;
  5599. }
  5600. m_BlockBytesAtD3D12Fetch[0] = m_BlockBytes[0];
  5601. m_BlockBytesAtD3D12Fetch[1] = m_BlockBytes[1];
  5602. m_OperationsSinceBudgetFetch = 0;
  5603. }
  5604. return FAILED(hrLocal) ? hrLocal : hrNonLocal;
  5605. }
  5606. #endif // #if D3D12MA_DXGI_1_4
  5607. void CurrentBudgetData::AddAllocation(UINT group, UINT64 allocationBytes)
  5608. {
  5609. ++m_AllocationCount[group];
  5610. m_AllocationBytes[group] += allocationBytes;
  5611. ++m_OperationsSinceBudgetFetch;
  5612. }
  5613. void CurrentBudgetData::RemoveAllocation(UINT group, UINT64 allocationBytes)
  5614. {
  5615. D3D12MA_ASSERT(m_AllocationBytes[group] >= allocationBytes);
  5616. D3D12MA_ASSERT(m_AllocationCount[group] > 0);
  5617. m_AllocationBytes[group] -= allocationBytes;
  5618. --m_AllocationCount[group];
  5619. ++m_OperationsSinceBudgetFetch;
  5620. }
  5621. void CurrentBudgetData::AddBlock(UINT group, UINT64 blockBytes)
  5622. {
  5623. ++m_BlockCount[group];
  5624. m_BlockBytes[group] += blockBytes;
  5625. ++m_OperationsSinceBudgetFetch;
  5626. }
  5627. void CurrentBudgetData::RemoveBlock(UINT group, UINT64 blockBytes)
  5628. {
  5629. D3D12MA_ASSERT(m_BlockBytes[group] >= blockBytes);
  5630. D3D12MA_ASSERT(m_BlockCount[group] > 0);
  5631. m_BlockBytes[group] -= blockBytes;
  5632. --m_BlockCount[group];
  5633. ++m_OperationsSinceBudgetFetch;
  5634. }
  5635. #endif // _D3D12MA_CURRENT_BUDGET_DATA_FUNCTIONS
  5636. #endif // _D3D12MA_CURRENT_BUDGET_DATA
  5637. #ifndef _D3D12MA_DEFRAGMENTATION_CONTEXT_PIMPL
  5638. class DefragmentationContextPimpl
  5639. {
  5640. D3D12MA_CLASS_NO_COPY(DefragmentationContextPimpl)
  5641. public:
  5642. DefragmentationContextPimpl(
  5643. AllocatorPimpl* hAllocator,
  5644. const DEFRAGMENTATION_DESC& desc,
  5645. BlockVector* poolVector);
  5646. ~DefragmentationContextPimpl();
  5647. void GetStats(DEFRAGMENTATION_STATS& outStats) { outStats = m_GlobalStats; }
  5648. const ALLOCATION_CALLBACKS& GetAllocs() const { return m_Moves.GetAllocs(); }
  5649. HRESULT DefragmentPassBegin(DEFRAGMENTATION_PASS_MOVE_INFO& moveInfo);
  5650. HRESULT DefragmentPassEnd(DEFRAGMENTATION_PASS_MOVE_INFO& moveInfo);
  5651. private:
  5652. // Max number of allocations to ignore due to size constraints before ending single pass
  5653. static const UINT8 MAX_ALLOCS_TO_IGNORE = 16;
  5654. enum class CounterStatus { Pass, Ignore, End };
  5655. struct FragmentedBlock
  5656. {
  5657. UINT32 data;
  5658. NormalBlock* block;
  5659. };
  5660. struct StateBalanced
  5661. {
  5662. UINT64 avgFreeSize = 0;
  5663. UINT64 avgAllocSize = UINT64_MAX;
  5664. };
  5665. struct MoveAllocationData
  5666. {
  5667. UINT64 size;
  5668. UINT64 alignment;
  5669. ALLOCATION_FLAGS flags;
  5670. DEFRAGMENTATION_MOVE move = {};
  5671. };
  5672. const UINT64 m_MaxPassBytes;
  5673. const UINT32 m_MaxPassAllocations;
  5674. Vector<DEFRAGMENTATION_MOVE> m_Moves;
  5675. UINT8 m_IgnoredAllocs = 0;
  5676. UINT32 m_Algorithm;
  5677. UINT32 m_BlockVectorCount;
  5678. BlockVector* m_PoolBlockVector;
  5679. BlockVector** m_pBlockVectors;
  5680. size_t m_ImmovableBlockCount = 0;
  5681. DEFRAGMENTATION_STATS m_GlobalStats = { 0 };
  5682. DEFRAGMENTATION_STATS m_PassStats = { 0 };
  5683. void* m_AlgorithmState = NULL;
  5684. static MoveAllocationData GetMoveData(AllocHandle handle, BlockMetadata* metadata);
  5685. CounterStatus CheckCounters(UINT64 bytes);
  5686. bool IncrementCounters(UINT64 bytes);
  5687. bool ReallocWithinBlock(BlockVector& vector, NormalBlock* block);
  5688. bool AllocInOtherBlock(size_t start, size_t end, MoveAllocationData& data, BlockVector& vector);
  5689. bool ComputeDefragmentation(BlockVector& vector, size_t index);
  5690. bool ComputeDefragmentation_Fast(BlockVector& vector);
  5691. bool ComputeDefragmentation_Balanced(BlockVector& vector, size_t index, bool update);
  5692. bool ComputeDefragmentation_Full(BlockVector& vector);
  5693. void UpdateVectorStatistics(BlockVector& vector, StateBalanced& state);
  5694. };
  5695. #endif // _D3D12MA_DEFRAGMENTATION_CONTEXT_PIMPL
  5696. #ifndef _D3D12MA_POOL_PIMPL
  5697. class PoolPimpl
  5698. {
  5699. friend class Allocator;
  5700. friend struct PoolListItemTraits;
  5701. public:
  5702. PoolPimpl(AllocatorPimpl* allocator, const POOL_DESC& desc);
  5703. ~PoolPimpl();
  5704. AllocatorPimpl* GetAllocator() const { return m_Allocator; }
  5705. const POOL_DESC& GetDesc() const { return m_Desc; }
  5706. bool SupportsCommittedAllocations() const { return m_Desc.BlockSize == 0; }
  5707. LPCWSTR GetName() const { return m_Name; }
  5708. BlockVector* GetBlockVector() { return m_BlockVector; }
  5709. CommittedAllocationList* GetCommittedAllocationList() { return SupportsCommittedAllocations() ? &m_CommittedAllocations : NULL; }
  5710. HRESULT Init();
  5711. void GetStatistics(Statistics& outStats);
  5712. void CalculateStatistics(DetailedStatistics& outStats);
  5713. void AddDetailedStatistics(DetailedStatistics& inoutStats);
  5714. void SetName(LPCWSTR Name);
  5715. private:
  5716. AllocatorPimpl* m_Allocator; // Externally owned object.
  5717. POOL_DESC m_Desc;
  5718. BlockVector* m_BlockVector; // Owned object.
  5719. CommittedAllocationList m_CommittedAllocations;
  5720. wchar_t* m_Name;
  5721. PoolPimpl* m_PrevPool = NULL;
  5722. PoolPimpl* m_NextPool = NULL;
  5723. void FreeName();
  5724. };
  5725. struct PoolListItemTraits
  5726. {
  5727. using ItemType = PoolPimpl;
  5728. static ItemType* GetPrev(const ItemType* item) { return item->m_PrevPool; }
  5729. static ItemType* GetNext(const ItemType* item) { return item->m_NextPool; }
  5730. static ItemType*& AccessPrev(ItemType* item) { return item->m_PrevPool; }
  5731. static ItemType*& AccessNext(ItemType* item) { return item->m_NextPool; }
  5732. };
  5733. #endif // _D3D12MA_POOL_PIMPL
  5734. #ifndef _D3D12MA_ALLOCATOR_PIMPL
  5735. class AllocatorPimpl
  5736. {
  5737. friend class Allocator;
  5738. friend class Pool;
  5739. public:
  5740. std::atomic_uint32_t m_RefCount = {1};
  5741. CurrentBudgetData m_Budget;
  5742. AllocatorPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks, const ALLOCATOR_DESC& desc);
  5743. ~AllocatorPimpl();
  5744. ID3D12Device* GetDevice() const { return m_Device; }
  5745. #ifdef __ID3D12Device1_INTERFACE_DEFINED__
  5746. ID3D12Device1* GetDevice1() const { return m_Device1; }
  5747. #endif
  5748. #ifdef __ID3D12Device4_INTERFACE_DEFINED__
  5749. ID3D12Device4* GetDevice4() const { return m_Device4; }
  5750. #endif
  5751. #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  5752. ID3D12Device8* GetDevice8() const { return m_Device8; }
  5753. #endif
  5754. // Shortcut for "Allocation Callbacks", because this function is called so often.
  5755. const ALLOCATION_CALLBACKS& GetAllocs() const { return m_AllocationCallbacks; }
  5756. const D3D12_FEATURE_DATA_D3D12_OPTIONS& GetD3D12Options() const { return m_D3D12Options; }
  5757. BOOL IsUMA() const { return m_D3D12Architecture.UMA; }
  5758. BOOL IsCacheCoherentUMA() const { return m_D3D12Architecture.CacheCoherentUMA; }
  5759. bool SupportsResourceHeapTier2() const { return m_D3D12Options.ResourceHeapTier >= D3D12_RESOURCE_HEAP_TIER_2; }
  5760. bool UseMutex() const { return m_UseMutex; }
  5761. AllocationObjectAllocator& GetAllocationObjectAllocator() { return m_AllocationObjectAllocator; }
  5762. UINT GetCurrentFrameIndex() const { return m_CurrentFrameIndex.load(); }
  5763. /*
  5764. If SupportsResourceHeapTier2():
  5765. 0: D3D12_HEAP_TYPE_DEFAULT
  5766. 1: D3D12_HEAP_TYPE_UPLOAD
  5767. 2: D3D12_HEAP_TYPE_READBACK
  5768. else:
  5769. 0: D3D12_HEAP_TYPE_DEFAULT + buffer
  5770. 1: D3D12_HEAP_TYPE_DEFAULT + texture
  5771. 2: D3D12_HEAP_TYPE_DEFAULT + texture RT or DS
  5772. 3: D3D12_HEAP_TYPE_UPLOAD + buffer
  5773. 4: D3D12_HEAP_TYPE_UPLOAD + texture
  5774. 5: D3D12_HEAP_TYPE_UPLOAD + texture RT or DS
  5775. 6: D3D12_HEAP_TYPE_READBACK + buffer
  5776. 7: D3D12_HEAP_TYPE_READBACK + texture
  5777. 8: D3D12_HEAP_TYPE_READBACK + texture RT or DS
  5778. */
  5779. UINT GetDefaultPoolCount() const { return SupportsResourceHeapTier2() ? 3 : 9; }
  5780. BlockVector** GetDefaultPools() { return m_BlockVectors; }
  5781. HRESULT Init(const ALLOCATOR_DESC& desc);
  5782. bool HeapFlagsFulfillResourceHeapTier(D3D12_HEAP_FLAGS flags) const;
  5783. UINT StandardHeapTypeToMemorySegmentGroup(D3D12_HEAP_TYPE heapType) const;
  5784. UINT HeapPropertiesToMemorySegmentGroup(const D3D12_HEAP_PROPERTIES& heapProps) const;
  5785. UINT64 GetMemoryCapacity(UINT memorySegmentGroup) const;
  5786. HRESULT CreatePlacedResourceWrap(
  5787. ID3D12Heap *pHeap,
  5788. UINT64 HeapOffset,
  5789. const CREATE_RESOURCE_PARAMS& createParams,
  5790. REFIID riidResource,
  5791. void** ppvResource);
  5792. HRESULT CreateResource(
  5793. const ALLOCATION_DESC* pAllocDesc,
  5794. const CREATE_RESOURCE_PARAMS& createParams,
  5795. Allocation** ppAllocation,
  5796. REFIID riidResource,
  5797. void** ppvResource);
  5798. HRESULT CreateAliasingResource(
  5799. Allocation* pAllocation,
  5800. UINT64 AllocationLocalOffset,
  5801. const CREATE_RESOURCE_PARAMS& createParams,
  5802. REFIID riidResource,
  5803. void** ppvResource);
  5804. HRESULT AllocateMemory(
  5805. const ALLOCATION_DESC* pAllocDesc,
  5806. const D3D12_RESOURCE_ALLOCATION_INFO* pAllocInfo,
  5807. Allocation** ppAllocation);
  5808. // Unregisters allocation from the collection of dedicated allocations.
  5809. // Allocation object must be deleted externally afterwards.
  5810. void FreeCommittedMemory(Allocation* allocation);
  5811. // Unregisters allocation from the collection of placed allocations.
  5812. // Allocation object must be deleted externally afterwards.
  5813. void FreePlacedMemory(Allocation* allocation);
  5814. // Unregisters allocation from the collection of dedicated allocations and destroys associated heap.
  5815. // Allocation object must be deleted externally afterwards.
  5816. void FreeHeapMemory(Allocation* allocation);
  5817. void SetResidencyPriority(ID3D12Pageable* obj, D3D12_RESIDENCY_PRIORITY priority) const;
  5818. void SetCurrentFrameIndex(UINT frameIndex);
  5819. // For more deailed stats use outCutomHeaps to access statistics divided into L0 and L1 group
  5820. void CalculateStatistics(TotalStatistics& outStats, DetailedStatistics outCutomHeaps[2] = NULL);
  5821. void GetBudget(Budget* outLocalBudget, Budget* outNonLocalBudget);
  5822. void GetBudgetForHeapType(Budget& outBudget, D3D12_HEAP_TYPE heapType);
  5823. void BuildStatsString(WCHAR** ppStatsString, BOOL detailedMap);
  5824. void FreeStatsString(WCHAR* pStatsString);
  5825. private:
  5826. using PoolList = IntrusiveLinkedList<PoolListItemTraits>;
  5827. const bool m_UseMutex;
  5828. const bool m_AlwaysCommitted;
  5829. const bool m_MsaaAlwaysCommitted;
  5830. bool m_DefaultPoolsNotZeroed = false;
  5831. ID3D12Device* m_Device; // AddRef
  5832. #ifdef __ID3D12Device1_INTERFACE_DEFINED__
  5833. ID3D12Device1* m_Device1 = NULL; // AddRef, optional
  5834. #endif
  5835. #ifdef __ID3D12Device4_INTERFACE_DEFINED__
  5836. ID3D12Device4* m_Device4 = NULL; // AddRef, optional
  5837. #endif
  5838. #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  5839. ID3D12Device8* m_Device8 = NULL; // AddRef, optional
  5840. #endif
  5841. #ifdef __ID3D12Device10_INTERFACE_DEFINED__
  5842. ID3D12Device10* m_Device10 = NULL; // AddRef, optional
  5843. #endif
  5844. IDXGIAdapter* m_Adapter; // AddRef
  5845. #if D3D12MA_DXGI_1_4
  5846. IDXGIAdapter3* m_Adapter3 = NULL; // AddRef, optional
  5847. #endif
  5848. UINT64 m_PreferredBlockSize;
  5849. ALLOCATION_CALLBACKS m_AllocationCallbacks;
  5850. D3D12MA_ATOMIC_UINT32 m_CurrentFrameIndex;
  5851. DXGI_ADAPTER_DESC m_AdapterDesc;
  5852. D3D12_FEATURE_DATA_D3D12_OPTIONS m_D3D12Options;
  5853. D3D12_FEATURE_DATA_ARCHITECTURE m_D3D12Architecture;
  5854. AllocationObjectAllocator m_AllocationObjectAllocator;
  5855. D3D12MA_RW_MUTEX m_PoolsMutex[HEAP_TYPE_COUNT];
  5856. PoolList m_Pools[HEAP_TYPE_COUNT];
  5857. // Default pools.
  5858. BlockVector* m_BlockVectors[DEFAULT_POOL_MAX_COUNT];
  5859. CommittedAllocationList m_CommittedAllocations[STANDARD_HEAP_TYPE_COUNT];
  5860. /*
  5861. Heuristics that decides whether a resource should better be placed in its own,
  5862. dedicated allocation (committed resource rather than placed resource).
  5863. */
  5864. template<typename D3D12_RESOURCE_DESC_T>
  5865. static bool PrefersCommittedAllocation(const D3D12_RESOURCE_DESC_T& resourceDesc);
  5866. // Allocates and registers new committed resource with implicit heap, as dedicated allocation.
  5867. // Creates and returns Allocation object and optionally D3D12 resource.
  5868. HRESULT AllocateCommittedResource(
  5869. const CommittedAllocationParameters& committedAllocParams,
  5870. UINT64 resourceSize, bool withinBudget, void* pPrivateData,
  5871. const CREATE_RESOURCE_PARAMS& createParams,
  5872. Allocation** ppAllocation, REFIID riidResource, void** ppvResource);
  5873. // Allocates and registers new heap without any resources placed in it, as dedicated allocation.
  5874. // Creates and returns Allocation object.
  5875. HRESULT AllocateHeap(
  5876. const CommittedAllocationParameters& committedAllocParams,
  5877. const D3D12_RESOURCE_ALLOCATION_INFO& allocInfo, bool withinBudget,
  5878. void* pPrivateData, Allocation** ppAllocation);
  5879. template<typename D3D12_RESOURCE_DESC_T>
  5880. HRESULT CalcAllocationParams(const ALLOCATION_DESC& allocDesc, UINT64 allocSize,
  5881. const D3D12_RESOURCE_DESC_T* resDesc, // Optional
  5882. BlockVector*& outBlockVector, CommittedAllocationParameters& outCommittedAllocationParams, bool& outPreferCommitted);
  5883. // Returns UINT32_MAX if index cannot be calculcated.
  5884. UINT CalcDefaultPoolIndex(const ALLOCATION_DESC& allocDesc, ResourceClass resourceClass) const;
  5885. void CalcDefaultPoolParams(D3D12_HEAP_TYPE& outHeapType, D3D12_HEAP_FLAGS& outHeapFlags, UINT index) const;
  5886. // Registers Pool object in m_Pools.
  5887. void RegisterPool(Pool* pool, D3D12_HEAP_TYPE heapType);
  5888. // Unregisters Pool object from m_Pools.
  5889. void UnregisterPool(Pool* pool, D3D12_HEAP_TYPE heapType);
  5890. HRESULT UpdateD3D12Budget();
  5891. D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfoNative(const D3D12_RESOURCE_DESC& resourceDesc) const;
  5892. #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  5893. D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfoNative(const D3D12_RESOURCE_DESC1& resourceDesc) const;
  5894. #endif
  5895. template<typename D3D12_RESOURCE_DESC_T>
  5896. D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfo(D3D12_RESOURCE_DESC_T& inOutResourceDesc) const;
  5897. bool NewAllocationWithinBudget(D3D12_HEAP_TYPE heapType, UINT64 size);
  5898. // Writes object { } with data of given budget.
  5899. static void WriteBudgetToJson(JsonWriter& json, const Budget& budget);
  5900. };
  5901. #ifndef _D3D12MA_ALLOCATOR_PIMPL_FUNCTINOS
  5902. AllocatorPimpl::AllocatorPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks, const ALLOCATOR_DESC& desc)
  5903. : m_UseMutex((desc.Flags & ALLOCATOR_FLAG_SINGLETHREADED) == 0),
  5904. m_AlwaysCommitted((desc.Flags & ALLOCATOR_FLAG_ALWAYS_COMMITTED) != 0),
  5905. m_MsaaAlwaysCommitted((desc.Flags & ALLOCATOR_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED) != 0),
  5906. m_Device(desc.pDevice),
  5907. m_Adapter(desc.pAdapter),
  5908. m_PreferredBlockSize(desc.PreferredBlockSize != 0 ? desc.PreferredBlockSize : D3D12MA_DEFAULT_BLOCK_SIZE),
  5909. m_AllocationCallbacks(allocationCallbacks),
  5910. m_CurrentFrameIndex(0),
  5911. // Below this line don't use allocationCallbacks but m_AllocationCallbacks!!!
  5912. m_AllocationObjectAllocator(m_AllocationCallbacks)
  5913. {
  5914. // desc.pAllocationCallbacks intentionally ignored here, preprocessed by CreateAllocator.
  5915. ZeroMemory(&m_D3D12Options, sizeof(m_D3D12Options));
  5916. ZeroMemory(&m_D3D12Architecture, sizeof(m_D3D12Architecture));
  5917. ZeroMemory(m_BlockVectors, sizeof(m_BlockVectors));
  5918. for (UINT i = 0; i < STANDARD_HEAP_TYPE_COUNT; ++i)
  5919. {
  5920. m_CommittedAllocations[i].Init(
  5921. m_UseMutex,
  5922. (D3D12_HEAP_TYPE)(D3D12_HEAP_TYPE_DEFAULT + i),
  5923. NULL); // pool
  5924. }
  5925. m_Device->AddRef();
  5926. m_Adapter->AddRef();
  5927. }
  5928. HRESULT AllocatorPimpl::Init(const ALLOCATOR_DESC& desc)
  5929. {
  5930. #if D3D12MA_DXGI_1_4
  5931. desc.pAdapter->QueryInterface(D3D12MA_IID_PPV_ARGS(&m_Adapter3));
  5932. #endif
  5933. #ifdef __ID3D12Device1_INTERFACE_DEFINED__
  5934. m_Device->QueryInterface(D3D12MA_IID_PPV_ARGS(&m_Device1));
  5935. #endif
  5936. #ifdef __ID3D12Device4_INTERFACE_DEFINED__
  5937. m_Device->QueryInterface(D3D12MA_IID_PPV_ARGS(&m_Device4));
  5938. #endif
  5939. #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  5940. m_Device->QueryInterface(D3D12MA_IID_PPV_ARGS(&m_Device8));
  5941. if((desc.Flags & ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED) != 0)
  5942. {
  5943. D3D12_FEATURE_DATA_D3D12_OPTIONS7 options7 = {};
  5944. if(SUCCEEDED(m_Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &options7, sizeof(options7))))
  5945. {
  5946. // DEFAULT_POOLS_NOT_ZEROED both supported and enabled by the user.
  5947. m_DefaultPoolsNotZeroed = true;
  5948. }
  5949. }
  5950. #endif
  5951. #ifdef __ID3D12Device10_INTERFACE_DEFINED__
  5952. m_Device->QueryInterface(D3D12MA_IID_PPV_ARGS(&m_Device10));
  5953. #endif
  5954. HRESULT hr = m_Adapter->GetDesc(&m_AdapterDesc);
  5955. if (FAILED(hr))
  5956. {
  5957. return hr;
  5958. }
  5959. hr = m_Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &m_D3D12Options, sizeof(m_D3D12Options));
  5960. if (FAILED(hr))
  5961. {
  5962. return hr;
  5963. }
  5964. #ifdef D3D12MA_FORCE_RESOURCE_HEAP_TIER
  5965. m_D3D12Options.ResourceHeapTier = (D3D12MA_FORCE_RESOURCE_HEAP_TIER);
  5966. #endif
  5967. hr = m_Device->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE, &m_D3D12Architecture, sizeof(m_D3D12Architecture));
  5968. if (FAILED(hr))
  5969. {
  5970. m_D3D12Architecture.UMA = FALSE;
  5971. m_D3D12Architecture.CacheCoherentUMA = FALSE;
  5972. }
  5973. D3D12_HEAP_PROPERTIES heapProps = {};
  5974. const UINT defaultPoolCount = GetDefaultPoolCount();
  5975. for (UINT i = 0; i < defaultPoolCount; ++i)
  5976. {
  5977. D3D12_HEAP_FLAGS heapFlags;
  5978. CalcDefaultPoolParams(heapProps.Type, heapFlags, i);
  5979. #if D3D12MA_CREATE_NOT_ZEROED_AVAILABLE
  5980. if(m_DefaultPoolsNotZeroed)
  5981. {
  5982. heapFlags |= D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;
  5983. }
  5984. #endif
  5985. m_BlockVectors[i] = D3D12MA_NEW(GetAllocs(), BlockVector)(
  5986. this, // hAllocator
  5987. heapProps, // heapType
  5988. heapFlags, // heapFlags
  5989. m_PreferredBlockSize,
  5990. 0, // minBlockCount
  5991. SIZE_MAX, // maxBlockCount
  5992. false, // explicitBlockSize
  5993. D3D12MA_DEBUG_ALIGNMENT, // minAllocationAlignment
  5994. 0, // Default algorithm,
  5995. m_MsaaAlwaysCommitted,
  5996. NULL, // pProtectedSession
  5997. D3D12_RESIDENCY_PRIORITY_NONE); // residencyPriority
  5998. // No need to call m_pBlockVectors[i]->CreateMinBlocks here, becase minBlockCount is 0.
  5999. }
  6000. #if D3D12MA_DXGI_1_4
  6001. UpdateD3D12Budget();
  6002. #endif
  6003. return S_OK;
  6004. }
  6005. AllocatorPimpl::~AllocatorPimpl()
  6006. {
  6007. #ifdef __ID3D12Device10_INTERFACE_DEFINED__
  6008. SAFE_RELEASE(m_Device10);
  6009. #endif
  6010. #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  6011. SAFE_RELEASE(m_Device8);
  6012. #endif
  6013. #ifdef __ID3D12Device4_INTERFACE_DEFINED__
  6014. SAFE_RELEASE(m_Device4);
  6015. #endif
  6016. #ifdef __ID3D12Device1_INTERFACE_DEFINED__
  6017. SAFE_RELEASE(m_Device1);
  6018. #endif
  6019. #if D3D12MA_DXGI_1_4
  6020. SAFE_RELEASE(m_Adapter3);
  6021. #endif
  6022. SAFE_RELEASE(m_Adapter);
  6023. SAFE_RELEASE(m_Device);
  6024. for (UINT i = DEFAULT_POOL_MAX_COUNT; i--; )
  6025. {
  6026. D3D12MA_DELETE(GetAllocs(), m_BlockVectors[i]);
  6027. }
  6028. for (UINT i = HEAP_TYPE_COUNT; i--; )
  6029. {
  6030. if (!m_Pools[i].IsEmpty())
  6031. {
  6032. D3D12MA_ASSERT(0 && "Unfreed pools found!");
  6033. }
  6034. }
  6035. }
  6036. bool AllocatorPimpl::HeapFlagsFulfillResourceHeapTier(D3D12_HEAP_FLAGS flags) const
  6037. {
  6038. if (SupportsResourceHeapTier2())
  6039. {
  6040. return true;
  6041. }
  6042. else
  6043. {
  6044. const bool allowBuffers = (flags & D3D12_HEAP_FLAG_DENY_BUFFERS) == 0;
  6045. const bool allowRtDsTextures = (flags & D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES) == 0;
  6046. const bool allowNonRtDsTextures = (flags & D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES) == 0;
  6047. const uint8_t allowedGroupCount = (allowBuffers ? 1 : 0) + (allowRtDsTextures ? 1 : 0) + (allowNonRtDsTextures ? 1 : 0);
  6048. return allowedGroupCount == 1;
  6049. }
  6050. }
  6051. UINT AllocatorPimpl::StandardHeapTypeToMemorySegmentGroup(D3D12_HEAP_TYPE heapType) const
  6052. {
  6053. D3D12MA_ASSERT(IsHeapTypeStandard(heapType));
  6054. if (IsUMA())
  6055. return DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY;
  6056. return heapType == D3D12_HEAP_TYPE_DEFAULT ?
  6057. DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY : DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY;
  6058. }
  6059. UINT AllocatorPimpl::HeapPropertiesToMemorySegmentGroup(const D3D12_HEAP_PROPERTIES& heapProps) const
  6060. {
  6061. if (IsUMA())
  6062. return DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY;
  6063. if (heapProps.MemoryPoolPreference == D3D12_MEMORY_POOL_UNKNOWN)
  6064. return StandardHeapTypeToMemorySegmentGroup(heapProps.Type);
  6065. return heapProps.MemoryPoolPreference == D3D12_MEMORY_POOL_L1 ?
  6066. DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY : DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY;
  6067. }
  6068. UINT64 AllocatorPimpl::GetMemoryCapacity(UINT memorySegmentGroup) const
  6069. {
  6070. switch (memorySegmentGroup)
  6071. {
  6072. case DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY:
  6073. return IsUMA() ?
  6074. m_AdapterDesc.DedicatedVideoMemory + m_AdapterDesc.SharedSystemMemory : m_AdapterDesc.DedicatedVideoMemory;
  6075. case DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY:
  6076. return IsUMA() ? 0 : m_AdapterDesc.SharedSystemMemory;
  6077. default:
  6078. D3D12MA_ASSERT(0);
  6079. return UINT64_MAX;
  6080. }
  6081. }
  6082. HRESULT AllocatorPimpl::CreatePlacedResourceWrap(
  6083. ID3D12Heap *pHeap,
  6084. UINT64 HeapOffset,
  6085. const CREATE_RESOURCE_PARAMS& createParams,
  6086. REFIID riidResource,
  6087. void** ppvResource)
  6088. {
  6089. #ifdef __ID3D12Device10_INTERFACE_DEFINED__
  6090. if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_LAYOUT)
  6091. {
  6092. if (!m_Device10)
  6093. {
  6094. return E_NOINTERFACE;
  6095. }
  6096. return m_Device10->CreatePlacedResource2(pHeap, HeapOffset,
  6097. createParams.GetResourceDesc1(), createParams.GetInitialLayout(),
  6098. createParams.GetOptimizedClearValue(), createParams.GetNumCastableFormats(),
  6099. createParams.GetCastableFormats(), riidResource, ppvResource);
  6100. } else
  6101. #endif
  6102. #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  6103. if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1)
  6104. {
  6105. if (!m_Device8)
  6106. {
  6107. return E_NOINTERFACE;
  6108. }
  6109. return m_Device8->CreatePlacedResource1(pHeap, HeapOffset,
  6110. createParams.GetResourceDesc1(), createParams.GetInitialResourceState(),
  6111. createParams.GetOptimizedClearValue(), riidResource, ppvResource);
  6112. } else
  6113. #endif
  6114. if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE)
  6115. {
  6116. return m_Device->CreatePlacedResource(pHeap, HeapOffset,
  6117. createParams.GetResourceDesc(), createParams.GetInitialResourceState(),
  6118. createParams.GetOptimizedClearValue(), riidResource, ppvResource);
  6119. }
  6120. else
  6121. {
  6122. D3D12MA_ASSERT(0);
  6123. return E_INVALIDARG;
  6124. }
  6125. }
  6126. HRESULT AllocatorPimpl::CreateResource(
  6127. const ALLOCATION_DESC* pAllocDesc,
  6128. const CREATE_RESOURCE_PARAMS& createParams,
  6129. Allocation** ppAllocation,
  6130. REFIID riidResource,
  6131. void** ppvResource)
  6132. {
  6133. D3D12MA_ASSERT(pAllocDesc && createParams.GetBaseResourceDesc() && ppAllocation);
  6134. *ppAllocation = NULL;
  6135. if (ppvResource)
  6136. {
  6137. *ppvResource = NULL;
  6138. }
  6139. CREATE_RESOURCE_PARAMS finalCreateParams = createParams;
  6140. D3D12_RESOURCE_DESC finalResourceDesc;
  6141. #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  6142. D3D12_RESOURCE_DESC1 finalResourceDesc1;
  6143. #endif
  6144. D3D12_RESOURCE_ALLOCATION_INFO resAllocInfo;
  6145. if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE)
  6146. {
  6147. finalResourceDesc = *createParams.GetResourceDesc();
  6148. finalCreateParams.AccessResourceDesc() = &finalResourceDesc;
  6149. resAllocInfo = GetResourceAllocationInfo(finalResourceDesc);
  6150. }
  6151. #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  6152. else if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1)
  6153. {
  6154. if (!m_Device8)
  6155. {
  6156. return E_NOINTERFACE;
  6157. }
  6158. finalResourceDesc1 = *createParams.GetResourceDesc1();
  6159. finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
  6160. resAllocInfo = GetResourceAllocationInfo(finalResourceDesc1);
  6161. }
  6162. #endif
  6163. #ifdef __ID3D12Device10_INTERFACE_DEFINED__
  6164. else if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_LAYOUT)
  6165. {
  6166. if (!m_Device10)
  6167. {
  6168. return E_NOINTERFACE;
  6169. }
  6170. finalResourceDesc1 = *createParams.GetResourceDesc1();
  6171. finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
  6172. resAllocInfo = GetResourceAllocationInfo(finalResourceDesc1);
  6173. }
  6174. #endif
  6175. else
  6176. {
  6177. D3D12MA_ASSERT(0);
  6178. return E_INVALIDARG;
  6179. }
  6180. D3D12MA_ASSERT(IsPow2(resAllocInfo.Alignment));
  6181. D3D12MA_ASSERT(resAllocInfo.SizeInBytes > 0);
  6182. BlockVector* blockVector = NULL;
  6183. CommittedAllocationParameters committedAllocationParams = {};
  6184. bool preferCommitted = false;
  6185. HRESULT hr;
  6186. #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  6187. if (createParams.Variant >= CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1)
  6188. {
  6189. hr = CalcAllocationParams<D3D12_RESOURCE_DESC1>(*pAllocDesc, resAllocInfo.SizeInBytes,
  6190. createParams.GetResourceDesc1(),
  6191. blockVector, committedAllocationParams, preferCommitted);
  6192. }
  6193. else
  6194. #endif
  6195. {
  6196. hr = CalcAllocationParams<D3D12_RESOURCE_DESC>(*pAllocDesc, resAllocInfo.SizeInBytes,
  6197. createParams.GetResourceDesc(),
  6198. blockVector, committedAllocationParams, preferCommitted);
  6199. }
  6200. if (FAILED(hr))
  6201. return hr;
  6202. const bool withinBudget = (pAllocDesc->Flags & ALLOCATION_FLAG_WITHIN_BUDGET) != 0;
  6203. hr = E_INVALIDARG;
  6204. if (committedAllocationParams.IsValid() && preferCommitted)
  6205. {
  6206. hr = AllocateCommittedResource(committedAllocationParams,
  6207. resAllocInfo.SizeInBytes, withinBudget, pAllocDesc->pPrivateData,
  6208. finalCreateParams, ppAllocation, riidResource, ppvResource);
  6209. if (SUCCEEDED(hr))
  6210. return hr;
  6211. }
  6212. if (blockVector != NULL)
  6213. {
  6214. hr = blockVector->CreateResource(resAllocInfo.SizeInBytes, resAllocInfo.Alignment,
  6215. *pAllocDesc, finalCreateParams,
  6216. ppAllocation, riidResource, ppvResource);
  6217. if (SUCCEEDED(hr))
  6218. return hr;
  6219. }
  6220. if (committedAllocationParams.IsValid() && !preferCommitted)
  6221. {
  6222. hr = AllocateCommittedResource(committedAllocationParams,
  6223. resAllocInfo.SizeInBytes, withinBudget, pAllocDesc->pPrivateData,
  6224. finalCreateParams, ppAllocation, riidResource, ppvResource);
  6225. if (SUCCEEDED(hr))
  6226. return hr;
  6227. }
  6228. return hr;
  6229. }
  6230. HRESULT AllocatorPimpl::AllocateMemory(
  6231. const ALLOCATION_DESC* pAllocDesc,
  6232. const D3D12_RESOURCE_ALLOCATION_INFO* pAllocInfo,
  6233. Allocation** ppAllocation)
  6234. {
  6235. *ppAllocation = NULL;
  6236. BlockVector* blockVector = NULL;
  6237. CommittedAllocationParameters committedAllocationParams = {};
  6238. bool preferCommitted = false;
  6239. HRESULT hr = CalcAllocationParams<D3D12_RESOURCE_DESC>(*pAllocDesc, pAllocInfo->SizeInBytes,
  6240. NULL, // pResDesc
  6241. blockVector, committedAllocationParams, preferCommitted);
  6242. if (FAILED(hr))
  6243. return hr;
  6244. const bool withinBudget = (pAllocDesc->Flags & ALLOCATION_FLAG_WITHIN_BUDGET) != 0;
  6245. hr = E_INVALIDARG;
  6246. if (committedAllocationParams.IsValid() && preferCommitted)
  6247. {
  6248. hr = AllocateHeap(committedAllocationParams, *pAllocInfo, withinBudget, pAllocDesc->pPrivateData, ppAllocation);
  6249. if (SUCCEEDED(hr))
  6250. return hr;
  6251. }
  6252. if (blockVector != NULL)
  6253. {
  6254. hr = blockVector->Allocate(pAllocInfo->SizeInBytes, pAllocInfo->Alignment,
  6255. *pAllocDesc, 1, (Allocation**)ppAllocation);
  6256. if (SUCCEEDED(hr))
  6257. return hr;
  6258. }
  6259. if (committedAllocationParams.IsValid() && !preferCommitted)
  6260. {
  6261. hr = AllocateHeap(committedAllocationParams, *pAllocInfo, withinBudget, pAllocDesc->pPrivateData, ppAllocation);
  6262. if (SUCCEEDED(hr))
  6263. return hr;
  6264. }
  6265. return hr;
  6266. }
  6267. HRESULT AllocatorPimpl::CreateAliasingResource(
  6268. Allocation* pAllocation,
  6269. UINT64 AllocationLocalOffset,
  6270. const CREATE_RESOURCE_PARAMS& createParams,
  6271. REFIID riidResource,
  6272. void** ppvResource)
  6273. {
  6274. *ppvResource = NULL;
  6275. CREATE_RESOURCE_PARAMS finalCreateParams = createParams;
  6276. D3D12_RESOURCE_DESC finalResourceDesc;
  6277. #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  6278. D3D12_RESOURCE_DESC1 finalResourceDesc1;
  6279. #endif
  6280. D3D12_RESOURCE_ALLOCATION_INFO resAllocInfo;
  6281. if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE)
  6282. {
  6283. finalResourceDesc = *createParams.GetResourceDesc();
  6284. finalCreateParams.AccessResourceDesc() = &finalResourceDesc;
  6285. resAllocInfo = GetResourceAllocationInfo(finalResourceDesc);
  6286. }
  6287. #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  6288. else if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1)
  6289. {
  6290. if (!m_Device8)
  6291. {
  6292. return E_NOINTERFACE;
  6293. }
  6294. finalResourceDesc1 = *createParams.GetResourceDesc1();
  6295. finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
  6296. resAllocInfo = GetResourceAllocationInfo(finalResourceDesc1);
  6297. }
  6298. #endif
  6299. #ifdef __ID3D12Device10_INTERFACE_DEFINED__
  6300. else if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_LAYOUT)
  6301. {
  6302. if (!m_Device10)
  6303. {
  6304. return E_NOINTERFACE;
  6305. }
  6306. finalResourceDesc1 = *createParams.GetResourceDesc1();
  6307. finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
  6308. resAllocInfo = GetResourceAllocationInfo(finalResourceDesc1);
  6309. }
  6310. #endif
  6311. else
  6312. {
  6313. D3D12MA_ASSERT(0);
  6314. return E_INVALIDARG;
  6315. }
  6316. D3D12MA_ASSERT(IsPow2(resAllocInfo.Alignment));
  6317. D3D12MA_ASSERT(resAllocInfo.SizeInBytes > 0);
  6318. ID3D12Heap* const existingHeap = pAllocation->GetHeap();
  6319. const UINT64 existingOffset = pAllocation->GetOffset();
  6320. const UINT64 existingSize = pAllocation->GetSize();
  6321. const UINT64 newOffset = existingOffset + AllocationLocalOffset;
  6322. if (existingHeap == NULL ||
  6323. AllocationLocalOffset + resAllocInfo.SizeInBytes > existingSize ||
  6324. newOffset % resAllocInfo.Alignment != 0)
  6325. {
  6326. return E_INVALIDARG;
  6327. }
  6328. return CreatePlacedResourceWrap(existingHeap, newOffset, finalCreateParams, riidResource, ppvResource);
  6329. }
  6330. void AllocatorPimpl::FreeCommittedMemory(Allocation* allocation)
  6331. {
  6332. D3D12MA_ASSERT(allocation && allocation->m_PackedData.GetType() == Allocation::TYPE_COMMITTED);
  6333. CommittedAllocationList* const allocList = allocation->m_Committed.list;
  6334. allocList->Unregister(allocation);
  6335. const UINT memSegmentGroup = allocList->GetMemorySegmentGroup(this);
  6336. const UINT64 allocSize = allocation->GetSize();
  6337. m_Budget.RemoveAllocation(memSegmentGroup, allocSize);
  6338. m_Budget.RemoveBlock(memSegmentGroup, allocSize);
  6339. }
  6340. void AllocatorPimpl::FreePlacedMemory(Allocation* allocation)
  6341. {
  6342. D3D12MA_ASSERT(allocation && allocation->m_PackedData.GetType() == Allocation::TYPE_PLACED);
  6343. NormalBlock* const block = allocation->m_Placed.block;
  6344. D3D12MA_ASSERT(block);
  6345. BlockVector* const blockVector = block->GetBlockVector();
  6346. D3D12MA_ASSERT(blockVector);
  6347. m_Budget.RemoveAllocation(HeapPropertiesToMemorySegmentGroup(block->GetHeapProperties()), allocation->GetSize());
  6348. blockVector->Free(allocation);
  6349. }
  6350. void AllocatorPimpl::FreeHeapMemory(Allocation* allocation)
  6351. {
  6352. D3D12MA_ASSERT(allocation && allocation->m_PackedData.GetType() == Allocation::TYPE_HEAP);
  6353. CommittedAllocationList* const allocList = allocation->m_Committed.list;
  6354. allocList->Unregister(allocation);
  6355. SAFE_RELEASE(allocation->m_Heap.heap);
  6356. const UINT memSegmentGroup = allocList->GetMemorySegmentGroup(this);
  6357. const UINT64 allocSize = allocation->GetSize();
  6358. m_Budget.RemoveAllocation(memSegmentGroup, allocSize);
  6359. m_Budget.RemoveBlock(memSegmentGroup, allocSize);
  6360. }
  6361. void AllocatorPimpl::SetResidencyPriority(ID3D12Pageable* obj, D3D12_RESIDENCY_PRIORITY priority) const
  6362. {
  6363. #ifdef __ID3D12Device1_INTERFACE_DEFINED__
  6364. if (priority != D3D12_RESIDENCY_PRIORITY_NONE && m_Device1)
  6365. {
  6366. // Intentionally ignoring the result.
  6367. m_Device1->SetResidencyPriority(1, &obj, &priority);
  6368. }
  6369. #endif
  6370. }
  6371. void AllocatorPimpl::SetCurrentFrameIndex(UINT frameIndex)
  6372. {
  6373. m_CurrentFrameIndex.store(frameIndex);
  6374. #if D3D12MA_DXGI_1_4
  6375. UpdateD3D12Budget();
  6376. #endif
  6377. }
  6378. void AllocatorPimpl::CalculateStatistics(TotalStatistics& outStats, DetailedStatistics outCutomHeaps[2])
  6379. {
  6380. // Init stats
  6381. for (size_t i = 0; i < HEAP_TYPE_COUNT; i++)
  6382. ClearDetailedStatistics(outStats.HeapType[i]);
  6383. for (size_t i = 0; i < DXGI_MEMORY_SEGMENT_GROUP_COUNT; i++)
  6384. ClearDetailedStatistics(outStats.MemorySegmentGroup[i]);
  6385. ClearDetailedStatistics(outStats.Total);
  6386. if (outCutomHeaps)
  6387. {
  6388. ClearDetailedStatistics(outCutomHeaps[0]);
  6389. ClearDetailedStatistics(outCutomHeaps[1]);
  6390. }
  6391. // Process default pools. 3 standard heap types only. Add them to outStats.HeapType[i].
  6392. if (SupportsResourceHeapTier2())
  6393. {
  6394. // DEFAULT, UPLOAD, READBACK.
  6395. for (size_t heapTypeIndex = 0; heapTypeIndex < STANDARD_HEAP_TYPE_COUNT; ++heapTypeIndex)
  6396. {
  6397. BlockVector* const pBlockVector = m_BlockVectors[heapTypeIndex];
  6398. D3D12MA_ASSERT(pBlockVector);
  6399. pBlockVector->AddDetailedStatistics(outStats.HeapType[heapTypeIndex]);
  6400. }
  6401. }
  6402. else
  6403. {
  6404. // DEFAULT, UPLOAD, READBACK.
  6405. for (size_t heapTypeIndex = 0; heapTypeIndex < STANDARD_HEAP_TYPE_COUNT; ++heapTypeIndex)
  6406. {
  6407. for (size_t heapSubType = 0; heapSubType < 3; ++heapSubType)
  6408. {
  6409. BlockVector* const pBlockVector = m_BlockVectors[heapTypeIndex * 3 + heapSubType];
  6410. D3D12MA_ASSERT(pBlockVector);
  6411. pBlockVector->AddDetailedStatistics(outStats.HeapType[heapTypeIndex]);
  6412. }
  6413. }
  6414. }
  6415. // Sum them up to memory segment groups.
  6416. AddDetailedStatistics(
  6417. outStats.MemorySegmentGroup[StandardHeapTypeToMemorySegmentGroup(D3D12_HEAP_TYPE_DEFAULT)],
  6418. outStats.HeapType[0]);
  6419. AddDetailedStatistics(
  6420. outStats.MemorySegmentGroup[StandardHeapTypeToMemorySegmentGroup(D3D12_HEAP_TYPE_UPLOAD)],
  6421. outStats.HeapType[1]);
  6422. AddDetailedStatistics(
  6423. outStats.MemorySegmentGroup[StandardHeapTypeToMemorySegmentGroup(D3D12_HEAP_TYPE_READBACK)],
  6424. outStats.HeapType[2]);
  6425. // Process custom pools.
  6426. DetailedStatistics tmpStats;
  6427. for (size_t heapTypeIndex = 0; heapTypeIndex < HEAP_TYPE_COUNT; ++heapTypeIndex)
  6428. {
  6429. MutexLockRead lock(m_PoolsMutex[heapTypeIndex], m_UseMutex);
  6430. PoolList& poolList = m_Pools[heapTypeIndex];
  6431. for (PoolPimpl* pool = poolList.Front(); pool != NULL; pool = poolList.GetNext(pool))
  6432. {
  6433. const D3D12_HEAP_PROPERTIES& poolHeapProps = pool->GetDesc().HeapProperties;
  6434. ClearDetailedStatistics(tmpStats);
  6435. pool->AddDetailedStatistics(tmpStats);
  6436. AddDetailedStatistics(
  6437. outStats.HeapType[heapTypeIndex], tmpStats);
  6438. UINT memorySegment = HeapPropertiesToMemorySegmentGroup(poolHeapProps);
  6439. AddDetailedStatistics(
  6440. outStats.MemorySegmentGroup[memorySegment], tmpStats);
  6441. if (outCutomHeaps)
  6442. AddDetailedStatistics(outCutomHeaps[memorySegment], tmpStats);
  6443. }
  6444. }
  6445. // Process committed allocations. 3 standard heap types only.
  6446. for (UINT heapTypeIndex = 0; heapTypeIndex < STANDARD_HEAP_TYPE_COUNT; ++heapTypeIndex)
  6447. {
  6448. ClearDetailedStatistics(tmpStats);
  6449. m_CommittedAllocations[heapTypeIndex].AddDetailedStatistics(tmpStats);
  6450. AddDetailedStatistics(
  6451. outStats.HeapType[heapTypeIndex], tmpStats);
  6452. AddDetailedStatistics(
  6453. outStats.MemorySegmentGroup[StandardHeapTypeToMemorySegmentGroup(IndexToHeapType(heapTypeIndex))], tmpStats);
  6454. }
  6455. // Sum up memory segment groups to totals.
  6456. AddDetailedStatistics(outStats.Total, outStats.MemorySegmentGroup[0]);
  6457. AddDetailedStatistics(outStats.Total, outStats.MemorySegmentGroup[1]);
  6458. D3D12MA_ASSERT(outStats.Total.Stats.BlockCount ==
  6459. outStats.MemorySegmentGroup[0].Stats.BlockCount + outStats.MemorySegmentGroup[1].Stats.BlockCount);
  6460. D3D12MA_ASSERT(outStats.Total.Stats.AllocationCount ==
  6461. outStats.MemorySegmentGroup[0].Stats.AllocationCount + outStats.MemorySegmentGroup[1].Stats.AllocationCount);
  6462. D3D12MA_ASSERT(outStats.Total.Stats.BlockBytes ==
  6463. outStats.MemorySegmentGroup[0].Stats.BlockBytes + outStats.MemorySegmentGroup[1].Stats.BlockBytes);
  6464. D3D12MA_ASSERT(outStats.Total.Stats.AllocationBytes ==
  6465. outStats.MemorySegmentGroup[0].Stats.AllocationBytes + outStats.MemorySegmentGroup[1].Stats.AllocationBytes);
  6466. D3D12MA_ASSERT(outStats.Total.UnusedRangeCount ==
  6467. outStats.MemorySegmentGroup[0].UnusedRangeCount + outStats.MemorySegmentGroup[1].UnusedRangeCount);
  6468. D3D12MA_ASSERT(outStats.Total.Stats.BlockCount ==
  6469. outStats.HeapType[0].Stats.BlockCount + outStats.HeapType[1].Stats.BlockCount +
  6470. outStats.HeapType[2].Stats.BlockCount + outStats.HeapType[3].Stats.BlockCount);
  6471. D3D12MA_ASSERT(outStats.Total.Stats.AllocationCount ==
  6472. outStats.HeapType[0].Stats.AllocationCount + outStats.HeapType[1].Stats.AllocationCount +
  6473. outStats.HeapType[2].Stats.AllocationCount + outStats.HeapType[3].Stats.AllocationCount);
  6474. D3D12MA_ASSERT(outStats.Total.Stats.BlockBytes ==
  6475. outStats.HeapType[0].Stats.BlockBytes + outStats.HeapType[1].Stats.BlockBytes +
  6476. outStats.HeapType[2].Stats.BlockBytes + outStats.HeapType[3].Stats.BlockBytes);
  6477. D3D12MA_ASSERT(outStats.Total.Stats.AllocationBytes ==
  6478. outStats.HeapType[0].Stats.AllocationBytes + outStats.HeapType[1].Stats.AllocationBytes +
  6479. outStats.HeapType[2].Stats.AllocationBytes + outStats.HeapType[3].Stats.AllocationBytes);
  6480. D3D12MA_ASSERT(outStats.Total.UnusedRangeCount ==
  6481. outStats.HeapType[0].UnusedRangeCount + outStats.HeapType[1].UnusedRangeCount +
  6482. outStats.HeapType[2].UnusedRangeCount + outStats.HeapType[3].UnusedRangeCount);
  6483. }
  6484. void AllocatorPimpl::GetBudget(Budget* outLocalBudget, Budget* outNonLocalBudget)
  6485. {
  6486. if (outLocalBudget)
  6487. m_Budget.GetStatistics(outLocalBudget->Stats, DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY);
  6488. if (outNonLocalBudget)
  6489. m_Budget.GetStatistics(outNonLocalBudget->Stats, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY);
  6490. #if D3D12MA_DXGI_1_4
  6491. if (m_Adapter3)
  6492. {
  6493. if (!m_Budget.ShouldUpdateBudget())
  6494. {
  6495. m_Budget.GetBudget(m_UseMutex,
  6496. outLocalBudget ? &outLocalBudget->UsageBytes : NULL,
  6497. outLocalBudget ? &outLocalBudget->BudgetBytes : NULL,
  6498. outNonLocalBudget ? &outNonLocalBudget->UsageBytes : NULL,
  6499. outNonLocalBudget ? &outNonLocalBudget->BudgetBytes : NULL);
  6500. }
  6501. else
  6502. {
  6503. UpdateD3D12Budget();
  6504. GetBudget(outLocalBudget, outNonLocalBudget); // Recursion
  6505. }
  6506. }
  6507. else
  6508. #endif
  6509. {
  6510. if (outLocalBudget)
  6511. {
  6512. outLocalBudget->UsageBytes = outLocalBudget->Stats.BlockBytes;
  6513. outLocalBudget->BudgetBytes = GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY) * 8 / 10; // 80% heuristics.
  6514. }
  6515. if (outNonLocalBudget)
  6516. {
  6517. outNonLocalBudget->UsageBytes = outNonLocalBudget->Stats.BlockBytes;
  6518. outNonLocalBudget->BudgetBytes = GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY) * 8 / 10; // 80% heuristics.
  6519. }
  6520. }
  6521. }
  6522. void AllocatorPimpl::GetBudgetForHeapType(Budget& outBudget, D3D12_HEAP_TYPE heapType)
  6523. {
  6524. switch (heapType)
  6525. {
  6526. case D3D12_HEAP_TYPE_DEFAULT:
  6527. GetBudget(&outBudget, NULL);
  6528. break;
  6529. case D3D12_HEAP_TYPE_UPLOAD:
  6530. case D3D12_HEAP_TYPE_READBACK:
  6531. GetBudget(NULL, &outBudget);
  6532. break;
  6533. default: D3D12MA_ASSERT(0);
  6534. }
  6535. }
  6536. void AllocatorPimpl::BuildStatsString(WCHAR** ppStatsString, BOOL detailedMap)
  6537. {
  6538. StringBuilder sb(GetAllocs());
  6539. {
  6540. Budget localBudget = {}, nonLocalBudget = {};
  6541. GetBudget(&localBudget, &nonLocalBudget);
  6542. TotalStatistics stats;
  6543. DetailedStatistics customHeaps[2];
  6544. CalculateStatistics(stats, customHeaps);
  6545. JsonWriter json(GetAllocs(), sb);
  6546. json.BeginObject();
  6547. {
  6548. json.WriteString(L"General");
  6549. json.BeginObject();
  6550. {
  6551. json.WriteString(L"API");
  6552. json.WriteString(L"Direct3D 12");
  6553. json.WriteString(L"GPU");
  6554. json.WriteString(m_AdapterDesc.Description);
  6555. json.WriteString(L"DedicatedVideoMemory");
  6556. json.WriteNumber((UINT64)m_AdapterDesc.DedicatedVideoMemory);
  6557. json.WriteString(L"DedicatedSystemMemory");
  6558. json.WriteNumber((UINT64)m_AdapterDesc.DedicatedSystemMemory);
  6559. json.WriteString(L"SharedSystemMemory");
  6560. json.WriteNumber((UINT64)m_AdapterDesc.SharedSystemMemory);
  6561. json.WriteString(L"ResourceHeapTier");
  6562. json.WriteNumber(static_cast<UINT>(m_D3D12Options.ResourceHeapTier));
  6563. json.WriteString(L"ResourceBindingTier");
  6564. json.WriteNumber(static_cast<UINT>(m_D3D12Options.ResourceBindingTier));
  6565. json.WriteString(L"TiledResourcesTier");
  6566. json.WriteNumber(static_cast<UINT>(m_D3D12Options.TiledResourcesTier));
  6567. json.WriteString(L"TileBasedRenderer");
  6568. json.WriteBool(m_D3D12Architecture.TileBasedRenderer);
  6569. json.WriteString(L"UMA");
  6570. json.WriteBool(m_D3D12Architecture.UMA);
  6571. json.WriteString(L"CacheCoherentUMA");
  6572. json.WriteBool(m_D3D12Architecture.CacheCoherentUMA);
  6573. }
  6574. json.EndObject();
  6575. }
  6576. {
  6577. json.WriteString(L"Total");
  6578. json.AddDetailedStatisticsInfoObject(stats.Total);
  6579. }
  6580. {
  6581. json.WriteString(L"MemoryInfo");
  6582. json.BeginObject();
  6583. {
  6584. json.WriteString(L"L0");
  6585. json.BeginObject();
  6586. {
  6587. json.WriteString(L"Budget");
  6588. WriteBudgetToJson(json, IsUMA() ? localBudget : nonLocalBudget); // When UMA device only L0 present as local
  6589. json.WriteString(L"Stats");
  6590. json.AddDetailedStatisticsInfoObject(stats.MemorySegmentGroup[!IsUMA()]);
  6591. json.WriteString(L"MemoryPools");
  6592. json.BeginObject();
  6593. {
  6594. if (IsUMA())
  6595. {
  6596. json.WriteString(L"DEFAULT");
  6597. json.BeginObject();
  6598. {
  6599. json.WriteString(L"Stats");
  6600. json.AddDetailedStatisticsInfoObject(stats.HeapType[0]);
  6601. }
  6602. json.EndObject();
  6603. }
  6604. json.WriteString(L"UPLOAD");
  6605. json.BeginObject();
  6606. {
  6607. json.WriteString(L"Stats");
  6608. json.AddDetailedStatisticsInfoObject(stats.HeapType[1]);
  6609. }
  6610. json.EndObject();
  6611. json.WriteString(L"READBACK");
  6612. json.BeginObject();
  6613. {
  6614. json.WriteString(L"Stats");
  6615. json.AddDetailedStatisticsInfoObject(stats.HeapType[2]);
  6616. }
  6617. json.EndObject();
  6618. json.WriteString(L"CUSTOM");
  6619. json.BeginObject();
  6620. {
  6621. json.WriteString(L"Stats");
  6622. json.AddDetailedStatisticsInfoObject(customHeaps[!IsUMA()]);
  6623. }
  6624. json.EndObject();
  6625. }
  6626. json.EndObject();
  6627. }
  6628. json.EndObject();
  6629. if (!IsUMA())
  6630. {
  6631. json.WriteString(L"L1");
  6632. json.BeginObject();
  6633. {
  6634. json.WriteString(L"Budget");
  6635. WriteBudgetToJson(json, localBudget);
  6636. json.WriteString(L"Stats");
  6637. json.AddDetailedStatisticsInfoObject(stats.MemorySegmentGroup[0]);
  6638. json.WriteString(L"MemoryPools");
  6639. json.BeginObject();
  6640. {
  6641. json.WriteString(L"DEFAULT");
  6642. json.BeginObject();
  6643. {
  6644. json.WriteString(L"Stats");
  6645. json.AddDetailedStatisticsInfoObject(stats.HeapType[0]);
  6646. }
  6647. json.EndObject();
  6648. json.WriteString(L"CUSTOM");
  6649. json.BeginObject();
  6650. {
  6651. json.WriteString(L"Stats");
  6652. json.AddDetailedStatisticsInfoObject(customHeaps[0]);
  6653. }
  6654. json.EndObject();
  6655. }
  6656. json.EndObject();
  6657. }
  6658. json.EndObject();
  6659. }
  6660. }
  6661. json.EndObject();
  6662. }
  6663. if (detailedMap)
  6664. {
  6665. const auto writeHeapInfo = [&](BlockVector* blockVector, CommittedAllocationList* committedAllocs, bool customHeap)
  6666. {
  6667. D3D12MA_ASSERT(blockVector);
  6668. D3D12_HEAP_FLAGS flags = blockVector->GetHeapFlags();
  6669. json.WriteString(L"Flags");
  6670. json.BeginArray(true);
  6671. {
  6672. if (flags & D3D12_HEAP_FLAG_SHARED)
  6673. json.WriteString(L"HEAP_FLAG_SHARED");
  6674. if (flags & D3D12_HEAP_FLAG_ALLOW_DISPLAY)
  6675. json.WriteString(L"HEAP_FLAG_ALLOW_DISPLAY");
  6676. if (flags & D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER)
  6677. json.WriteString(L"HEAP_FLAG_CROSS_ADAPTER");
  6678. if (flags & D3D12_HEAP_FLAG_HARDWARE_PROTECTED)
  6679. json.WriteString(L"HEAP_FLAG_HARDWARE_PROTECTED");
  6680. if (flags & D3D12_HEAP_FLAG_ALLOW_WRITE_WATCH)
  6681. json.WriteString(L"HEAP_FLAG_ALLOW_WRITE_WATCH");
  6682. if (flags & D3D12_HEAP_FLAG_ALLOW_SHADER_ATOMICS)
  6683. json.WriteString(L"HEAP_FLAG_ALLOW_SHADER_ATOMICS");
  6684. #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  6685. if (flags & D3D12_HEAP_FLAG_CREATE_NOT_RESIDENT)
  6686. json.WriteString(L"HEAP_FLAG_CREATE_NOT_RESIDENT");
  6687. if (flags & D3D12_HEAP_FLAG_CREATE_NOT_ZEROED)
  6688. json.WriteString(L"HEAP_FLAG_CREATE_NOT_ZEROED");
  6689. #endif
  6690. if (flags & D3D12_HEAP_FLAG_DENY_BUFFERS)
  6691. json.WriteString(L"HEAP_FLAG_DENY_BUFFERS");
  6692. if (flags & D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES)
  6693. json.WriteString(L"HEAP_FLAG_DENY_RT_DS_TEXTURES");
  6694. if (flags & D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES)
  6695. json.WriteString(L"HEAP_FLAG_DENY_NON_RT_DS_TEXTURES");
  6696. flags &= ~(D3D12_HEAP_FLAG_SHARED
  6697. | D3D12_HEAP_FLAG_DENY_BUFFERS
  6698. | D3D12_HEAP_FLAG_ALLOW_DISPLAY
  6699. | D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER
  6700. | D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES
  6701. | D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES
  6702. | D3D12_HEAP_FLAG_HARDWARE_PROTECTED
  6703. | D3D12_HEAP_FLAG_ALLOW_WRITE_WATCH
  6704. | D3D12_HEAP_FLAG_ALLOW_SHADER_ATOMICS);
  6705. #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  6706. flags &= ~(D3D12_HEAP_FLAG_CREATE_NOT_RESIDENT
  6707. | D3D12_HEAP_FLAG_CREATE_NOT_ZEROED);
  6708. #endif
  6709. if (flags != 0)
  6710. json.WriteNumber((UINT)flags);
  6711. if (customHeap)
  6712. {
  6713. const D3D12_HEAP_PROPERTIES& properties = blockVector->GetHeapProperties();
  6714. switch (properties.MemoryPoolPreference)
  6715. {
  6716. default:
  6717. D3D12MA_ASSERT(0);
  6718. case D3D12_MEMORY_POOL_UNKNOWN:
  6719. json.WriteString(L"MEMORY_POOL_UNKNOWN");
  6720. break;
  6721. case D3D12_MEMORY_POOL_L0:
  6722. json.WriteString(L"MEMORY_POOL_L0");
  6723. break;
  6724. case D3D12_MEMORY_POOL_L1:
  6725. json.WriteString(L"MEMORY_POOL_L1");
  6726. break;
  6727. }
  6728. switch (properties.CPUPageProperty)
  6729. {
  6730. default:
  6731. D3D12MA_ASSERT(0);
  6732. case D3D12_CPU_PAGE_PROPERTY_UNKNOWN:
  6733. json.WriteString(L"CPU_PAGE_PROPERTY_UNKNOWN");
  6734. break;
  6735. case D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE:
  6736. json.WriteString(L"CPU_PAGE_PROPERTY_NOT_AVAILABLE");
  6737. break;
  6738. case D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE:
  6739. json.WriteString(L"CPU_PAGE_PROPERTY_WRITE_COMBINE");
  6740. break;
  6741. case D3D12_CPU_PAGE_PROPERTY_WRITE_BACK:
  6742. json.WriteString(L"CPU_PAGE_PROPERTY_WRITE_BACK");
  6743. break;
  6744. }
  6745. }
  6746. }
  6747. json.EndArray();
  6748. json.WriteString(L"PreferredBlockSize");
  6749. json.WriteNumber(blockVector->GetPreferredBlockSize());
  6750. json.WriteString(L"Blocks");
  6751. blockVector->WriteBlockInfoToJson(json);
  6752. json.WriteString(L"DedicatedAllocations");
  6753. json.BeginArray();
  6754. if (committedAllocs)
  6755. committedAllocs->BuildStatsString(json);
  6756. json.EndArray();
  6757. };
  6758. json.WriteString(L"DefaultPools");
  6759. json.BeginObject();
  6760. {
  6761. if (SupportsResourceHeapTier2())
  6762. {
  6763. for (uint8_t heapType = 0; heapType < STANDARD_HEAP_TYPE_COUNT; ++heapType)
  6764. {
  6765. json.WriteString(HeapTypeNames[heapType]);
  6766. json.BeginObject();
  6767. writeHeapInfo(m_BlockVectors[heapType], m_CommittedAllocations + heapType, false);
  6768. json.EndObject();
  6769. }
  6770. }
  6771. else
  6772. {
  6773. for (uint8_t heapType = 0; heapType < STANDARD_HEAP_TYPE_COUNT; ++heapType)
  6774. {
  6775. for (uint8_t heapSubType = 0; heapSubType < 3; ++heapSubType)
  6776. {
  6777. static const WCHAR* const heapSubTypeName[] = {
  6778. L" - Buffers",
  6779. L" - Textures",
  6780. L" - Textures RT/DS",
  6781. };
  6782. json.BeginString(HeapTypeNames[heapType]);
  6783. json.EndString(heapSubTypeName[heapSubType]);
  6784. json.BeginObject();
  6785. writeHeapInfo(m_BlockVectors[heapType + heapSubType], m_CommittedAllocations + heapType, false);
  6786. json.EndObject();
  6787. }
  6788. }
  6789. }
  6790. }
  6791. json.EndObject();
  6792. json.WriteString(L"CustomPools");
  6793. json.BeginObject();
  6794. for (uint8_t heapTypeIndex = 0; heapTypeIndex < HEAP_TYPE_COUNT; ++heapTypeIndex)
  6795. {
  6796. MutexLockRead mutex(m_PoolsMutex[heapTypeIndex], m_UseMutex);
  6797. auto* item = m_Pools[heapTypeIndex].Front();
  6798. if (item != NULL)
  6799. {
  6800. size_t index = 0;
  6801. json.WriteString(HeapTypeNames[heapTypeIndex]);
  6802. json.BeginArray();
  6803. do
  6804. {
  6805. json.BeginObject();
  6806. json.WriteString(L"Name");
  6807. json.BeginString();
  6808. json.ContinueString(index++);
  6809. if (item->GetName())
  6810. {
  6811. json.ContinueString(L" - ");
  6812. json.ContinueString(item->GetName());
  6813. }
  6814. json.EndString();
  6815. writeHeapInfo(item->GetBlockVector(), item->GetCommittedAllocationList(), heapTypeIndex == 3);
  6816. json.EndObject();
  6817. } while ((item = PoolList::GetNext(item)) != NULL);
  6818. json.EndArray();
  6819. }
  6820. }
  6821. json.EndObject();
  6822. }
  6823. json.EndObject();
  6824. }
  6825. const size_t length = sb.GetLength();
  6826. WCHAR* result = AllocateArray<WCHAR>(GetAllocs(), length + 2);
  6827. result[0] = 0xFEFF;
  6828. memcpy(result + 1, sb.GetData(), length * sizeof(WCHAR));
  6829. result[length + 1] = L'\0';
  6830. *ppStatsString = result;
  6831. }
  6832. void AllocatorPimpl::FreeStatsString(WCHAR* pStatsString)
  6833. {
  6834. D3D12MA_ASSERT(pStatsString);
  6835. Free(GetAllocs(), pStatsString);
  6836. }
  6837. template<typename D3D12_RESOURCE_DESC_T>
  6838. bool AllocatorPimpl::PrefersCommittedAllocation(const D3D12_RESOURCE_DESC_T& resourceDesc)
  6839. {
  6840. // Intentional. It may change in the future.
  6841. return false;
  6842. }
  6843. HRESULT AllocatorPimpl::AllocateCommittedResource(
  6844. const CommittedAllocationParameters& committedAllocParams,
  6845. UINT64 resourceSize, bool withinBudget, void* pPrivateData,
  6846. const CREATE_RESOURCE_PARAMS& createParams,
  6847. Allocation** ppAllocation, REFIID riidResource, void** ppvResource)
  6848. {
  6849. D3D12MA_ASSERT(committedAllocParams.IsValid());
  6850. HRESULT hr;
  6851. ID3D12Resource* res = NULL;
  6852. // Allocate aliasing memory with explicit heap
  6853. if (committedAllocParams.m_CanAlias)
  6854. {
  6855. D3D12_RESOURCE_ALLOCATION_INFO heapAllocInfo = {};
  6856. heapAllocInfo.SizeInBytes = resourceSize;
  6857. heapAllocInfo.Alignment = HeapFlagsToAlignment(committedAllocParams.m_HeapFlags, m_MsaaAlwaysCommitted);
  6858. hr = AllocateHeap(committedAllocParams, heapAllocInfo, withinBudget, pPrivateData, ppAllocation);
  6859. if (SUCCEEDED(hr))
  6860. {
  6861. hr = CreatePlacedResourceWrap((*ppAllocation)->GetHeap(), 0,
  6862. createParams, D3D12MA_IID_PPV_ARGS(&res));
  6863. if (SUCCEEDED(hr))
  6864. {
  6865. if (ppvResource != NULL)
  6866. hr = res->QueryInterface(riidResource, ppvResource);
  6867. if (SUCCEEDED(hr))
  6868. {
  6869. (*ppAllocation)->SetResourcePointer(res, createParams.GetBaseResourceDesc());
  6870. return hr;
  6871. }
  6872. res->Release();
  6873. }
  6874. FreeHeapMemory(*ppAllocation);
  6875. }
  6876. return hr;
  6877. }
  6878. if (withinBudget &&
  6879. !NewAllocationWithinBudget(committedAllocParams.m_HeapProperties.Type, resourceSize))
  6880. {
  6881. return E_OUTOFMEMORY;
  6882. }
  6883. /* D3D12 ERROR:
  6884. * ID3D12Device::CreateCommittedResource:
  6885. * When creating a committed resource, D3D12_HEAP_FLAGS must not have either
  6886. * D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES,
  6887. * D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES,
  6888. * nor D3D12_HEAP_FLAG_DENY_BUFFERS set.
  6889. * These flags will be set automatically to correspond with the committed resource type.
  6890. *
  6891. * [ STATE_CREATION ERROR #640: CREATERESOURCEANDHEAP_INVALIDHEAPMISCFLAGS]
  6892. */
  6893. #ifdef __ID3D12Device10_INTERFACE_DEFINED__
  6894. if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_LAYOUT)
  6895. {
  6896. if (!m_Device10)
  6897. {
  6898. return E_NOINTERFACE;
  6899. }
  6900. hr = m_Device10->CreateCommittedResource3(
  6901. &committedAllocParams.m_HeapProperties,
  6902. committedAllocParams.m_HeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS,
  6903. createParams.GetResourceDesc1(), createParams.GetInitialLayout(),
  6904. createParams.GetOptimizedClearValue(), committedAllocParams.m_ProtectedSession,
  6905. createParams.GetNumCastableFormats(), createParams.GetCastableFormats(),
  6906. D3D12MA_IID_PPV_ARGS(&res));
  6907. } else
  6908. #endif
  6909. #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  6910. if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1)
  6911. {
  6912. if (!m_Device8)
  6913. {
  6914. return E_NOINTERFACE;
  6915. }
  6916. hr = m_Device8->CreateCommittedResource2(
  6917. &committedAllocParams.m_HeapProperties,
  6918. committedAllocParams.m_HeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS,
  6919. createParams.GetResourceDesc1(), createParams.GetInitialResourceState(),
  6920. createParams.GetOptimizedClearValue(), committedAllocParams.m_ProtectedSession,
  6921. D3D12MA_IID_PPV_ARGS(&res));
  6922. } else
  6923. #endif
  6924. if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE)
  6925. {
  6926. #ifdef __ID3D12Device4_INTERFACE_DEFINED__
  6927. if (m_Device4)
  6928. {
  6929. hr = m_Device4->CreateCommittedResource1(
  6930. &committedAllocParams.m_HeapProperties,
  6931. committedAllocParams.m_HeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS,
  6932. createParams.GetResourceDesc(), createParams.GetInitialResourceState(),
  6933. createParams.GetOptimizedClearValue(), committedAllocParams.m_ProtectedSession,
  6934. D3D12MA_IID_PPV_ARGS(&res));
  6935. }
  6936. else
  6937. #endif
  6938. {
  6939. if (committedAllocParams.m_ProtectedSession == NULL)
  6940. {
  6941. hr = m_Device->CreateCommittedResource(
  6942. &committedAllocParams.m_HeapProperties,
  6943. committedAllocParams.m_HeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS,
  6944. createParams.GetResourceDesc(), createParams.GetInitialResourceState(),
  6945. createParams.GetOptimizedClearValue(), D3D12MA_IID_PPV_ARGS(&res));
  6946. }
  6947. else
  6948. hr = E_NOINTERFACE;
  6949. }
  6950. }
  6951. else
  6952. {
  6953. D3D12MA_ASSERT(0);
  6954. return E_INVALIDARG;
  6955. }
  6956. if (SUCCEEDED(hr))
  6957. {
  6958. SetResidencyPriority(res, committedAllocParams.m_ResidencyPriority);
  6959. if (ppvResource != NULL)
  6960. {
  6961. hr = res->QueryInterface(riidResource, ppvResource);
  6962. }
  6963. if (SUCCEEDED(hr))
  6964. {
  6965. BOOL wasZeroInitialized = TRUE;
  6966. #if D3D12MA_CREATE_NOT_ZEROED_AVAILABLE
  6967. if((committedAllocParams.m_HeapFlags & D3D12_HEAP_FLAG_CREATE_NOT_ZEROED) != 0)
  6968. {
  6969. wasZeroInitialized = FALSE;
  6970. }
  6971. #endif
  6972. Allocation* alloc = m_AllocationObjectAllocator.Allocate(
  6973. this, resourceSize, createParams.GetBaseResourceDesc()->Alignment, wasZeroInitialized);
  6974. alloc->InitCommitted(committedAllocParams.m_List);
  6975. alloc->SetResourcePointer(res, createParams.GetBaseResourceDesc());
  6976. alloc->SetPrivateData(pPrivateData);
  6977. *ppAllocation = alloc;
  6978. committedAllocParams.m_List->Register(alloc);
  6979. const UINT memSegmentGroup = HeapPropertiesToMemorySegmentGroup(committedAllocParams.m_HeapProperties);
  6980. m_Budget.AddBlock(memSegmentGroup, resourceSize);
  6981. m_Budget.AddAllocation(memSegmentGroup, resourceSize);
  6982. }
  6983. else
  6984. {
  6985. res->Release();
  6986. }
  6987. }
  6988. return hr;
  6989. }
  6990. HRESULT AllocatorPimpl::AllocateHeap(
  6991. const CommittedAllocationParameters& committedAllocParams,
  6992. const D3D12_RESOURCE_ALLOCATION_INFO& allocInfo, bool withinBudget,
  6993. void* pPrivateData, Allocation** ppAllocation)
  6994. {
  6995. D3D12MA_ASSERT(committedAllocParams.IsValid());
  6996. *ppAllocation = nullptr;
  6997. if (withinBudget &&
  6998. !NewAllocationWithinBudget(committedAllocParams.m_HeapProperties.Type, allocInfo.SizeInBytes))
  6999. {
  7000. return E_OUTOFMEMORY;
  7001. }
  7002. D3D12_HEAP_DESC heapDesc = {};
  7003. heapDesc.SizeInBytes = allocInfo.SizeInBytes;
  7004. heapDesc.Properties = committedAllocParams.m_HeapProperties;
  7005. heapDesc.Alignment = allocInfo.Alignment;
  7006. heapDesc.Flags = committedAllocParams.m_HeapFlags;
  7007. HRESULT hr;
  7008. ID3D12Heap* heap = nullptr;
  7009. #ifdef __ID3D12Device4_INTERFACE_DEFINED__
  7010. if (m_Device4)
  7011. hr = m_Device4->CreateHeap1(&heapDesc, committedAllocParams.m_ProtectedSession, D3D12MA_IID_PPV_ARGS(&heap));
  7012. else
  7013. #endif
  7014. {
  7015. if (committedAllocParams.m_ProtectedSession == NULL)
  7016. hr = m_Device->CreateHeap(&heapDesc, D3D12MA_IID_PPV_ARGS(&heap));
  7017. else
  7018. hr = E_NOINTERFACE;
  7019. }
  7020. if (SUCCEEDED(hr))
  7021. {
  7022. SetResidencyPriority(heap, committedAllocParams.m_ResidencyPriority);
  7023. BOOL wasZeroInitialized = TRUE;
  7024. #if D3D12MA_CREATE_NOT_ZEROED_AVAILABLE
  7025. if((heapDesc.Flags & D3D12_HEAP_FLAG_CREATE_NOT_ZEROED) != 0)
  7026. {
  7027. wasZeroInitialized = FALSE;
  7028. }
  7029. #endif
  7030. (*ppAllocation) = m_AllocationObjectAllocator.Allocate(this, allocInfo.SizeInBytes, allocInfo.Alignment, wasZeroInitialized);
  7031. (*ppAllocation)->InitHeap(committedAllocParams.m_List, heap);
  7032. (*ppAllocation)->SetPrivateData(pPrivateData);
  7033. committedAllocParams.m_List->Register(*ppAllocation);
  7034. const UINT memSegmentGroup = HeapPropertiesToMemorySegmentGroup(committedAllocParams.m_HeapProperties);
  7035. m_Budget.AddBlock(memSegmentGroup, allocInfo.SizeInBytes);
  7036. m_Budget.AddAllocation(memSegmentGroup, allocInfo.SizeInBytes);
  7037. }
  7038. return hr;
  7039. }
  7040. template<typename D3D12_RESOURCE_DESC_T>
  7041. HRESULT AllocatorPimpl::CalcAllocationParams(const ALLOCATION_DESC& allocDesc, UINT64 allocSize,
  7042. const D3D12_RESOURCE_DESC_T* resDesc,
  7043. BlockVector*& outBlockVector, CommittedAllocationParameters& outCommittedAllocationParams, bool& outPreferCommitted)
  7044. {
  7045. outBlockVector = NULL;
  7046. outCommittedAllocationParams = CommittedAllocationParameters();
  7047. outPreferCommitted = false;
  7048. bool msaaAlwaysCommitted;
  7049. if (allocDesc.CustomPool != NULL)
  7050. {
  7051. PoolPimpl* const pool = allocDesc.CustomPool->m_Pimpl;
  7052. msaaAlwaysCommitted = pool->GetBlockVector()->DeniesMsaaTextures();
  7053. outBlockVector = pool->GetBlockVector();
  7054. const auto& desc = pool->GetDesc();
  7055. outCommittedAllocationParams.m_ProtectedSession = desc.pProtectedSession;
  7056. outCommittedAllocationParams.m_HeapProperties = desc.HeapProperties;
  7057. outCommittedAllocationParams.m_HeapFlags = desc.HeapFlags;
  7058. outCommittedAllocationParams.m_List = pool->GetCommittedAllocationList();
  7059. outCommittedAllocationParams.m_ResidencyPriority = pool->GetDesc().ResidencyPriority;
  7060. }
  7061. else
  7062. {
  7063. if (!IsHeapTypeStandard(allocDesc.HeapType))
  7064. {
  7065. return E_INVALIDARG;
  7066. }
  7067. msaaAlwaysCommitted = m_MsaaAlwaysCommitted;
  7068. outCommittedAllocationParams.m_HeapProperties = StandardHeapTypeToHeapProperties(allocDesc.HeapType);
  7069. outCommittedAllocationParams.m_HeapFlags = allocDesc.ExtraHeapFlags;
  7070. outCommittedAllocationParams.m_List = &m_CommittedAllocations[HeapTypeToIndex(allocDesc.HeapType)];
  7071. // outCommittedAllocationParams.m_ResidencyPriority intentionally left with default value.
  7072. const ResourceClass resourceClass = (resDesc != NULL) ?
  7073. ResourceDescToResourceClass(*resDesc) : HeapFlagsToResourceClass(allocDesc.ExtraHeapFlags);
  7074. const UINT defaultPoolIndex = CalcDefaultPoolIndex(allocDesc, resourceClass);
  7075. if (defaultPoolIndex != UINT32_MAX)
  7076. {
  7077. outBlockVector = m_BlockVectors[defaultPoolIndex];
  7078. const UINT64 preferredBlockSize = outBlockVector->GetPreferredBlockSize();
  7079. if (allocSize > preferredBlockSize)
  7080. {
  7081. outBlockVector = NULL;
  7082. }
  7083. else if (allocSize > preferredBlockSize / 2)
  7084. {
  7085. // Heuristics: Allocate committed memory if requested size if greater than half of preferred block size.
  7086. outPreferCommitted = true;
  7087. }
  7088. }
  7089. const D3D12_HEAP_FLAGS extraHeapFlags = allocDesc.ExtraHeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS;
  7090. if (outBlockVector != NULL && extraHeapFlags != 0)
  7091. {
  7092. outBlockVector = NULL;
  7093. }
  7094. }
  7095. if ((allocDesc.Flags & ALLOCATION_FLAG_COMMITTED) != 0 ||
  7096. m_AlwaysCommitted)
  7097. {
  7098. outBlockVector = NULL;
  7099. }
  7100. if ((allocDesc.Flags & ALLOCATION_FLAG_NEVER_ALLOCATE) != 0)
  7101. {
  7102. outCommittedAllocationParams.m_List = NULL;
  7103. }
  7104. outCommittedAllocationParams.m_CanAlias = allocDesc.Flags & ALLOCATION_FLAG_CAN_ALIAS;
  7105. if (resDesc != NULL)
  7106. {
  7107. if (resDesc->SampleDesc.Count > 1 && msaaAlwaysCommitted)
  7108. outBlockVector = NULL;
  7109. if (!outPreferCommitted && PrefersCommittedAllocation(*resDesc))
  7110. outPreferCommitted = true;
  7111. }
  7112. return (outBlockVector != NULL || outCommittedAllocationParams.m_List != NULL) ? S_OK : E_INVALIDARG;
  7113. }
  7114. UINT AllocatorPimpl::CalcDefaultPoolIndex(const ALLOCATION_DESC& allocDesc, ResourceClass resourceClass) const
  7115. {
  7116. D3D12_HEAP_FLAGS extraHeapFlags = allocDesc.ExtraHeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS;
  7117. #if D3D12MA_CREATE_NOT_ZEROED_AVAILABLE
  7118. // If allocator was created with ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED, also ignore
  7119. // D3D12_HEAP_FLAG_CREATE_NOT_ZEROED.
  7120. if(m_DefaultPoolsNotZeroed)
  7121. {
  7122. extraHeapFlags &= ~D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;
  7123. }
  7124. #endif
  7125. if (extraHeapFlags != 0)
  7126. {
  7127. return UINT32_MAX;
  7128. }
  7129. UINT poolIndex = UINT_MAX;
  7130. switch (allocDesc.HeapType)
  7131. {
  7132. case D3D12_HEAP_TYPE_DEFAULT: poolIndex = 0; break;
  7133. case D3D12_HEAP_TYPE_UPLOAD: poolIndex = 1; break;
  7134. case D3D12_HEAP_TYPE_READBACK: poolIndex = 2; break;
  7135. default: D3D12MA_ASSERT(0);
  7136. }
  7137. if (SupportsResourceHeapTier2())
  7138. return poolIndex;
  7139. else
  7140. {
  7141. switch (resourceClass)
  7142. {
  7143. case ResourceClass::Buffer:
  7144. return poolIndex * 3;
  7145. case ResourceClass::Non_RT_DS_Texture:
  7146. return poolIndex * 3 + 1;
  7147. case ResourceClass::RT_DS_Texture:
  7148. return poolIndex * 3 + 2;
  7149. default:
  7150. return UINT32_MAX;
  7151. }
  7152. }
  7153. }
  7154. void AllocatorPimpl::CalcDefaultPoolParams(D3D12_HEAP_TYPE& outHeapType, D3D12_HEAP_FLAGS& outHeapFlags, UINT index) const
  7155. {
  7156. outHeapType = D3D12_HEAP_TYPE_DEFAULT;
  7157. outHeapFlags = D3D12_HEAP_FLAG_NONE;
  7158. if (!SupportsResourceHeapTier2())
  7159. {
  7160. switch (index % 3)
  7161. {
  7162. case 0:
  7163. outHeapFlags = D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES | D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
  7164. break;
  7165. case 1:
  7166. outHeapFlags = D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES;
  7167. break;
  7168. case 2:
  7169. outHeapFlags = D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
  7170. break;
  7171. }
  7172. index /= 3;
  7173. }
  7174. switch (index)
  7175. {
  7176. case 0:
  7177. outHeapType = D3D12_HEAP_TYPE_DEFAULT;
  7178. break;
  7179. case 1:
  7180. outHeapType = D3D12_HEAP_TYPE_UPLOAD;
  7181. break;
  7182. case 2:
  7183. outHeapType = D3D12_HEAP_TYPE_READBACK;
  7184. break;
  7185. default:
  7186. D3D12MA_ASSERT(0);
  7187. }
  7188. }
  7189. void AllocatorPimpl::RegisterPool(Pool* pool, D3D12_HEAP_TYPE heapType)
  7190. {
  7191. const UINT heapTypeIndex = HeapTypeToIndex(heapType);
  7192. MutexLockWrite lock(m_PoolsMutex[heapTypeIndex], m_UseMutex);
  7193. m_Pools[heapTypeIndex].PushBack(pool->m_Pimpl);
  7194. }
  7195. void AllocatorPimpl::UnregisterPool(Pool* pool, D3D12_HEAP_TYPE heapType)
  7196. {
  7197. const UINT heapTypeIndex = HeapTypeToIndex(heapType);
  7198. MutexLockWrite lock(m_PoolsMutex[heapTypeIndex], m_UseMutex);
  7199. m_Pools[heapTypeIndex].Remove(pool->m_Pimpl);
  7200. }
  7201. HRESULT AllocatorPimpl::UpdateD3D12Budget()
  7202. {
  7203. #if D3D12MA_DXGI_1_4
  7204. if (m_Adapter3)
  7205. return m_Budget.UpdateBudget(m_Adapter3, m_UseMutex);
  7206. else
  7207. return E_NOINTERFACE;
  7208. #else
  7209. return S_OK;
  7210. #endif
  7211. }
  7212. D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfoNative(const D3D12_RESOURCE_DESC& resourceDesc) const
  7213. {
  7214. #if defined(_MSC_VER) || !defined(_WIN32)
  7215. return m_Device->GetResourceAllocationInfo(0, 1, &resourceDesc);
  7216. #else
  7217. D3D12_RESOURCE_ALLOCATION_INFO ret;
  7218. m_Device->GetResourceAllocationInfo(&ret, 0, 1, &resourceDesc);
  7219. return ret;
  7220. #endif
  7221. }
  7222. #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  7223. D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfoNative(const D3D12_RESOURCE_DESC1& resourceDesc) const
  7224. {
  7225. D3D12MA_ASSERT(m_Device8 != NULL);
  7226. D3D12_RESOURCE_ALLOCATION_INFO1 info1Unused;
  7227. #if defined(_MSC_VER) || !defined(_WIN32)
  7228. return m_Device8->GetResourceAllocationInfo2(0, 1, &resourceDesc, &info1Unused);
  7229. #else
  7230. D3D12_RESOURCE_ALLOCATION_INFO ret;
  7231. m_Device8->GetResourceAllocationInfo2(&ret, 0, 1, &resourceDesc, &info1Unused);
  7232. return ret;
  7233. #endif
  7234. }
  7235. #endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  7236. template<typename D3D12_RESOURCE_DESC_T>
  7237. D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfo(D3D12_RESOURCE_DESC_T& inOutResourceDesc) const
  7238. {
  7239. /* Optional optimization: Microsoft documentation says:
  7240. https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-getresourceallocationinfo
  7241. Your application can forgo using GetResourceAllocationInfo for buffer resources
  7242. (D3D12_RESOURCE_DIMENSION_BUFFER). Buffers have the same size on all adapters,
  7243. which is merely the smallest multiple of 64KB that's greater or equal to
  7244. D3D12_RESOURCE_DESC::Width.
  7245. */
  7246. if (inOutResourceDesc.Alignment == 0 &&
  7247. inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
  7248. {
  7249. return {
  7250. AlignUp<UINT64>(inOutResourceDesc.Width, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT), // SizeInBytes
  7251. D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT }; // Alignment
  7252. }
  7253. #if D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT
  7254. if (inOutResourceDesc.Alignment == 0 &&
  7255. inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D &&
  7256. (inOutResourceDesc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) == 0
  7257. #if D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT == 1
  7258. && CanUseSmallAlignment(inOutResourceDesc)
  7259. #endif
  7260. )
  7261. {
  7262. /*
  7263. The algorithm here is based on Microsoft sample: "Small Resources Sample"
  7264. https://github.com/microsoft/DirectX-Graphics-Samples/tree/master/Samples/Desktop/D3D12SmallResources
  7265. */
  7266. const UINT64 smallAlignmentToTry = inOutResourceDesc.SampleDesc.Count > 1 ?
  7267. D3D12_SMALL_MSAA_RESOURCE_PLACEMENT_ALIGNMENT :
  7268. D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT;
  7269. inOutResourceDesc.Alignment = smallAlignmentToTry;
  7270. const D3D12_RESOURCE_ALLOCATION_INFO smallAllocInfo = GetResourceAllocationInfoNative(inOutResourceDesc);
  7271. // Check if alignment requested has been granted.
  7272. if (smallAllocInfo.Alignment == smallAlignmentToTry)
  7273. {
  7274. return smallAllocInfo;
  7275. }
  7276. inOutResourceDesc.Alignment = 0; // Restore original
  7277. }
  7278. #endif // #if D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT
  7279. return GetResourceAllocationInfoNative(inOutResourceDesc);
  7280. }
  7281. bool AllocatorPimpl::NewAllocationWithinBudget(D3D12_HEAP_TYPE heapType, UINT64 size)
  7282. {
  7283. Budget budget = {};
  7284. GetBudgetForHeapType(budget, heapType);
  7285. return budget.UsageBytes + size <= budget.BudgetBytes;
  7286. }
  7287. void AllocatorPimpl::WriteBudgetToJson(JsonWriter& json, const Budget& budget)
  7288. {
  7289. json.BeginObject();
  7290. {
  7291. json.WriteString(L"BudgetBytes");
  7292. json.WriteNumber(budget.BudgetBytes);
  7293. json.WriteString(L"UsageBytes");
  7294. json.WriteNumber(budget.UsageBytes);
  7295. }
  7296. json.EndObject();
  7297. }
  7298. #endif // _D3D12MA_ALLOCATOR_PIMPL
  7299. #endif // _D3D12MA_ALLOCATOR_PIMPL
  7300. #ifndef _D3D12MA_VIRTUAL_BLOCK_PIMPL
  7301. class VirtualBlockPimpl
  7302. {
  7303. public:
  7304. const ALLOCATION_CALLBACKS m_AllocationCallbacks;
  7305. const UINT64 m_Size;
  7306. BlockMetadata* m_Metadata;
  7307. VirtualBlockPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks, const VIRTUAL_BLOCK_DESC& desc);
  7308. ~VirtualBlockPimpl();
  7309. };
  7310. #ifndef _D3D12MA_VIRTUAL_BLOCK_PIMPL_FUNCTIONS
  7311. VirtualBlockPimpl::VirtualBlockPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks, const VIRTUAL_BLOCK_DESC& desc)
  7312. : m_AllocationCallbacks(allocationCallbacks), m_Size(desc.Size)
  7313. {
  7314. switch (desc.Flags & VIRTUAL_BLOCK_FLAG_ALGORITHM_MASK)
  7315. {
  7316. case VIRTUAL_BLOCK_FLAG_ALGORITHM_LINEAR:
  7317. m_Metadata = D3D12MA_NEW(allocationCallbacks, BlockMetadata_Linear)(&m_AllocationCallbacks, true);
  7318. break;
  7319. default:
  7320. D3D12MA_ASSERT(0);
  7321. case 0:
  7322. m_Metadata = D3D12MA_NEW(allocationCallbacks, BlockMetadata_TLSF)(&m_AllocationCallbacks, true);
  7323. break;
  7324. }
  7325. m_Metadata->Init(m_Size);
  7326. }
  7327. VirtualBlockPimpl::~VirtualBlockPimpl()
  7328. {
  7329. D3D12MA_DELETE(m_AllocationCallbacks, m_Metadata);
  7330. }
  7331. #endif // _D3D12MA_VIRTUAL_BLOCK_PIMPL_FUNCTIONS
  7332. #endif // _D3D12MA_VIRTUAL_BLOCK_PIMPL
  7333. #ifndef _D3D12MA_MEMORY_BLOCK_FUNCTIONS
  7334. MemoryBlock::MemoryBlock(
  7335. AllocatorPimpl* allocator,
  7336. const D3D12_HEAP_PROPERTIES& heapProps,
  7337. D3D12_HEAP_FLAGS heapFlags,
  7338. UINT64 size,
  7339. UINT id)
  7340. : m_Allocator(allocator),
  7341. m_HeapProps(heapProps),
  7342. m_HeapFlags(heapFlags),
  7343. m_Size(size),
  7344. m_Id(id) {}
  7345. MemoryBlock::~MemoryBlock()
  7346. {
  7347. if (m_Heap)
  7348. {
  7349. m_Heap->Release();
  7350. m_Allocator->m_Budget.RemoveBlock(
  7351. m_Allocator->HeapPropertiesToMemorySegmentGroup(m_HeapProps), m_Size);
  7352. }
  7353. }
  7354. HRESULT MemoryBlock::Init(ID3D12ProtectedResourceSession* pProtectedSession, bool denyMsaaTextures)
  7355. {
  7356. D3D12MA_ASSERT(m_Heap == NULL && m_Size > 0);
  7357. D3D12_HEAP_DESC heapDesc = {};
  7358. heapDesc.SizeInBytes = m_Size;
  7359. heapDesc.Properties = m_HeapProps;
  7360. heapDesc.Alignment = HeapFlagsToAlignment(m_HeapFlags, denyMsaaTextures);
  7361. heapDesc.Flags = m_HeapFlags;
  7362. HRESULT hr;
  7363. #ifdef __ID3D12Device4_INTERFACE_DEFINED__
  7364. ID3D12Device4* const device4 = m_Allocator->GetDevice4();
  7365. if (device4)
  7366. hr = m_Allocator->GetDevice4()->CreateHeap1(&heapDesc, pProtectedSession, D3D12MA_IID_PPV_ARGS(&m_Heap));
  7367. else
  7368. #endif
  7369. {
  7370. if (pProtectedSession == NULL)
  7371. hr = m_Allocator->GetDevice()->CreateHeap(&heapDesc, D3D12MA_IID_PPV_ARGS(&m_Heap));
  7372. else
  7373. hr = E_NOINTERFACE;
  7374. }
  7375. if (SUCCEEDED(hr))
  7376. {
  7377. m_Allocator->m_Budget.AddBlock(
  7378. m_Allocator->HeapPropertiesToMemorySegmentGroup(m_HeapProps), m_Size);
  7379. }
  7380. return hr;
  7381. }
  7382. #endif // _D3D12MA_MEMORY_BLOCK_FUNCTIONS
  7383. #ifndef _D3D12MA_NORMAL_BLOCK_FUNCTIONS
  7384. NormalBlock::NormalBlock(
  7385. AllocatorPimpl* allocator,
  7386. BlockVector* blockVector,
  7387. const D3D12_HEAP_PROPERTIES& heapProps,
  7388. D3D12_HEAP_FLAGS heapFlags,
  7389. UINT64 size,
  7390. UINT id)
  7391. : MemoryBlock(allocator, heapProps, heapFlags, size, id),
  7392. m_pMetadata(NULL),
  7393. m_BlockVector(blockVector) {}
  7394. NormalBlock::~NormalBlock()
  7395. {
  7396. if (m_pMetadata != NULL)
  7397. {
  7398. // Define macro D3D12MA_DEBUG_LOG to receive the list of the unfreed allocations.
  7399. if (!m_pMetadata->IsEmpty())
  7400. m_pMetadata->DebugLogAllAllocations();
  7401. // THIS IS THE MOST IMPORTANT ASSERT IN THE ENTIRE LIBRARY!
  7402. // Hitting it means you have some memory leak - unreleased Allocation objects.
  7403. D3D12MA_ASSERT(m_pMetadata->IsEmpty() && "Some allocations were not freed before destruction of this memory block!");
  7404. D3D12MA_DELETE(m_Allocator->GetAllocs(), m_pMetadata);
  7405. }
  7406. }
  7407. HRESULT NormalBlock::Init(UINT32 algorithm, ID3D12ProtectedResourceSession* pProtectedSession, bool denyMsaaTextures)
  7408. {
  7409. HRESULT hr = MemoryBlock::Init(pProtectedSession, denyMsaaTextures);
  7410. if (FAILED(hr))
  7411. {
  7412. return hr;
  7413. }
  7414. switch (algorithm)
  7415. {
  7416. case POOL_FLAG_ALGORITHM_LINEAR:
  7417. m_pMetadata = D3D12MA_NEW(m_Allocator->GetAllocs(), BlockMetadata_Linear)(&m_Allocator->GetAllocs(), false);
  7418. break;
  7419. default:
  7420. D3D12MA_ASSERT(0);
  7421. case 0:
  7422. m_pMetadata = D3D12MA_NEW(m_Allocator->GetAllocs(), BlockMetadata_TLSF)(&m_Allocator->GetAllocs(), false);
  7423. break;
  7424. }
  7425. m_pMetadata->Init(m_Size);
  7426. return hr;
  7427. }
  7428. bool NormalBlock::Validate() const
  7429. {
  7430. D3D12MA_VALIDATE(GetHeap() &&
  7431. m_pMetadata &&
  7432. m_pMetadata->GetSize() != 0 &&
  7433. m_pMetadata->GetSize() == GetSize());
  7434. return m_pMetadata->Validate();
  7435. }
  7436. #endif // _D3D12MA_NORMAL_BLOCK_FUNCTIONS
  7437. #ifndef _D3D12MA_COMMITTED_ALLOCATION_LIST_FUNCTIONS
  7438. void CommittedAllocationList::Init(bool useMutex, D3D12_HEAP_TYPE heapType, PoolPimpl* pool)
  7439. {
  7440. m_UseMutex = useMutex;
  7441. m_HeapType = heapType;
  7442. m_Pool = pool;
  7443. }
  7444. CommittedAllocationList::~CommittedAllocationList()
  7445. {
  7446. if (!m_AllocationList.IsEmpty())
  7447. {
  7448. D3D12MA_ASSERT(0 && "Unfreed committed allocations found!");
  7449. }
  7450. }
  7451. UINT CommittedAllocationList::GetMemorySegmentGroup(AllocatorPimpl* allocator) const
  7452. {
  7453. if (m_Pool)
  7454. return allocator->HeapPropertiesToMemorySegmentGroup(m_Pool->GetDesc().HeapProperties);
  7455. else
  7456. return allocator->StandardHeapTypeToMemorySegmentGroup(m_HeapType);
  7457. }
  7458. void CommittedAllocationList::AddStatistics(Statistics& inoutStats)
  7459. {
  7460. MutexLockRead lock(m_Mutex, m_UseMutex);
  7461. for (Allocation* alloc = m_AllocationList.Front();
  7462. alloc != NULL; alloc = m_AllocationList.GetNext(alloc))
  7463. {
  7464. const UINT64 size = alloc->GetSize();
  7465. inoutStats.BlockCount++;
  7466. inoutStats.AllocationCount++;
  7467. inoutStats.BlockBytes += size;
  7468. inoutStats.AllocationBytes += size;
  7469. }
  7470. }
  7471. void CommittedAllocationList::AddDetailedStatistics(DetailedStatistics& inoutStats)
  7472. {
  7473. MutexLockRead lock(m_Mutex, m_UseMutex);
  7474. for (Allocation* alloc = m_AllocationList.Front();
  7475. alloc != NULL; alloc = m_AllocationList.GetNext(alloc))
  7476. {
  7477. const UINT64 size = alloc->GetSize();
  7478. inoutStats.Stats.BlockCount++;
  7479. inoutStats.Stats.BlockBytes += size;
  7480. AddDetailedStatisticsAllocation(inoutStats, size);
  7481. }
  7482. }
  7483. void CommittedAllocationList::BuildStatsString(JsonWriter& json)
  7484. {
  7485. MutexLockRead lock(m_Mutex, m_UseMutex);
  7486. for (Allocation* alloc = m_AllocationList.Front();
  7487. alloc != NULL; alloc = m_AllocationList.GetNext(alloc))
  7488. {
  7489. json.BeginObject(true);
  7490. json.AddAllocationToObject(*alloc);
  7491. json.EndObject();
  7492. }
  7493. }
  7494. void CommittedAllocationList::Register(Allocation* alloc)
  7495. {
  7496. MutexLockWrite lock(m_Mutex, m_UseMutex);
  7497. m_AllocationList.PushBack(alloc);
  7498. }
  7499. void CommittedAllocationList::Unregister(Allocation* alloc)
  7500. {
  7501. MutexLockWrite lock(m_Mutex, m_UseMutex);
  7502. m_AllocationList.Remove(alloc);
  7503. }
  7504. #endif // _D3D12MA_COMMITTED_ALLOCATION_LIST_FUNCTIONS
  7505. #ifndef _D3D12MA_BLOCK_VECTOR_FUNCTIONS
  7506. BlockVector::BlockVector(
  7507. AllocatorPimpl* hAllocator,
  7508. const D3D12_HEAP_PROPERTIES& heapProps,
  7509. D3D12_HEAP_FLAGS heapFlags,
  7510. UINT64 preferredBlockSize,
  7511. size_t minBlockCount,
  7512. size_t maxBlockCount,
  7513. bool explicitBlockSize,
  7514. UINT64 minAllocationAlignment,
  7515. UINT32 algorithm,
  7516. bool denyMsaaTextures,
  7517. ID3D12ProtectedResourceSession* pProtectedSession,
  7518. D3D12_RESIDENCY_PRIORITY residencyPriority)
  7519. : m_hAllocator(hAllocator),
  7520. m_HeapProps(heapProps),
  7521. m_HeapFlags(heapFlags),
  7522. m_PreferredBlockSize(preferredBlockSize),
  7523. m_MinBlockCount(minBlockCount),
  7524. m_MaxBlockCount(maxBlockCount),
  7525. m_ExplicitBlockSize(explicitBlockSize),
  7526. m_MinAllocationAlignment(minAllocationAlignment),
  7527. m_Algorithm(algorithm),
  7528. m_DenyMsaaTextures(denyMsaaTextures),
  7529. m_ProtectedSession(pProtectedSession),
  7530. m_ResidencyPriority(residencyPriority),
  7531. m_HasEmptyBlock(false),
  7532. m_Blocks(hAllocator->GetAllocs()),
  7533. m_NextBlockId(0) {}
  7534. BlockVector::~BlockVector()
  7535. {
  7536. for (size_t i = m_Blocks.size(); i--; )
  7537. {
  7538. D3D12MA_DELETE(m_hAllocator->GetAllocs(), m_Blocks[i]);
  7539. }
  7540. }
  7541. HRESULT BlockVector::CreateMinBlocks()
  7542. {
  7543. for (size_t i = 0; i < m_MinBlockCount; ++i)
  7544. {
  7545. HRESULT hr = CreateBlock(m_PreferredBlockSize, NULL);
  7546. if (FAILED(hr))
  7547. {
  7548. return hr;
  7549. }
  7550. }
  7551. return S_OK;
  7552. }
  7553. bool BlockVector::IsEmpty()
  7554. {
  7555. MutexLockRead lock(m_Mutex, m_hAllocator->UseMutex());
  7556. return m_Blocks.empty();
  7557. }
  7558. HRESULT BlockVector::Allocate(
  7559. UINT64 size,
  7560. UINT64 alignment,
  7561. const ALLOCATION_DESC& allocDesc,
  7562. size_t allocationCount,
  7563. Allocation** pAllocations)
  7564. {
  7565. size_t allocIndex;
  7566. HRESULT hr = S_OK;
  7567. {
  7568. MutexLockWrite lock(m_Mutex, m_hAllocator->UseMutex());
  7569. for (allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
  7570. {
  7571. hr = AllocatePage(
  7572. size,
  7573. alignment,
  7574. allocDesc,
  7575. pAllocations + allocIndex);
  7576. if (FAILED(hr))
  7577. {
  7578. break;
  7579. }
  7580. }
  7581. }
  7582. if (FAILED(hr))
  7583. {
  7584. // Free all already created allocations.
  7585. while (allocIndex--)
  7586. {
  7587. Free(pAllocations[allocIndex]);
  7588. }
  7589. ZeroMemory(pAllocations, sizeof(Allocation*) * allocationCount);
  7590. }
  7591. return hr;
  7592. }
  7593. void BlockVector::Free(Allocation* hAllocation)
  7594. {
  7595. NormalBlock* pBlockToDelete = NULL;
  7596. bool budgetExceeded = false;
  7597. if (IsHeapTypeStandard(m_HeapProps.Type))
  7598. {
  7599. Budget budget = {};
  7600. m_hAllocator->GetBudgetForHeapType(budget, m_HeapProps.Type);
  7601. budgetExceeded = budget.UsageBytes >= budget.BudgetBytes;
  7602. }
  7603. // Scope for lock.
  7604. {
  7605. MutexLockWrite lock(m_Mutex, m_hAllocator->UseMutex());
  7606. NormalBlock* pBlock = hAllocation->m_Placed.block;
  7607. pBlock->m_pMetadata->Free(hAllocation->GetAllocHandle());
  7608. D3D12MA_HEAVY_ASSERT(pBlock->Validate());
  7609. const size_t blockCount = m_Blocks.size();
  7610. // pBlock became empty after this deallocation.
  7611. if (pBlock->m_pMetadata->IsEmpty())
  7612. {
  7613. // Already has empty Allocation. We don't want to have two, so delete this one.
  7614. if ((m_HasEmptyBlock || budgetExceeded) &&
  7615. blockCount > m_MinBlockCount)
  7616. {
  7617. pBlockToDelete = pBlock;
  7618. Remove(pBlock);
  7619. }
  7620. // We now have first empty block.
  7621. else
  7622. {
  7623. m_HasEmptyBlock = true;
  7624. }
  7625. }
  7626. // pBlock didn't become empty, but we have another empty block - find and free that one.
  7627. // (This is optional, heuristics.)
  7628. else if (m_HasEmptyBlock && blockCount > m_MinBlockCount)
  7629. {
  7630. NormalBlock* pLastBlock = m_Blocks.back();
  7631. if (pLastBlock->m_pMetadata->IsEmpty())
  7632. {
  7633. pBlockToDelete = pLastBlock;
  7634. m_Blocks.pop_back();
  7635. m_HasEmptyBlock = false;
  7636. }
  7637. }
  7638. IncrementallySortBlocks();
  7639. }
  7640. // Destruction of a free Allocation. Deferred until this point, outside of mutex
  7641. // lock, for performance reason.
  7642. if (pBlockToDelete != NULL)
  7643. {
  7644. D3D12MA_DELETE(m_hAllocator->GetAllocs(), pBlockToDelete);
  7645. }
  7646. }
  7647. HRESULT BlockVector::CreateResource(
  7648. UINT64 size,
  7649. UINT64 alignment,
  7650. const ALLOCATION_DESC& allocDesc,
  7651. const CREATE_RESOURCE_PARAMS& createParams,
  7652. Allocation** ppAllocation,
  7653. REFIID riidResource,
  7654. void** ppvResource)
  7655. {
  7656. HRESULT hr = Allocate(size, alignment, allocDesc, 1, ppAllocation);
  7657. if (SUCCEEDED(hr))
  7658. {
  7659. ID3D12Resource* res = NULL;
  7660. hr = m_hAllocator->CreatePlacedResourceWrap(
  7661. (*ppAllocation)->m_Placed.block->GetHeap(),
  7662. (*ppAllocation)->GetOffset(),
  7663. createParams,
  7664. D3D12MA_IID_PPV_ARGS(&res));
  7665. if (SUCCEEDED(hr))
  7666. {
  7667. if (ppvResource != NULL)
  7668. {
  7669. hr = res->QueryInterface(riidResource, ppvResource);
  7670. }
  7671. if (SUCCEEDED(hr))
  7672. {
  7673. (*ppAllocation)->SetResourcePointer(res, createParams.GetBaseResourceDesc());
  7674. }
  7675. else
  7676. {
  7677. res->Release();
  7678. SAFE_RELEASE(*ppAllocation);
  7679. }
  7680. }
  7681. else
  7682. {
  7683. SAFE_RELEASE(*ppAllocation);
  7684. }
  7685. }
  7686. return hr;
  7687. }
  7688. void BlockVector::AddStatistics(Statistics& inoutStats)
  7689. {
  7690. MutexLockRead lock(m_Mutex, m_hAllocator->UseMutex());
  7691. for (size_t i = 0; i < m_Blocks.size(); ++i)
  7692. {
  7693. const NormalBlock* const pBlock = m_Blocks[i];
  7694. D3D12MA_ASSERT(pBlock);
  7695. D3D12MA_HEAVY_ASSERT(pBlock->Validate());
  7696. pBlock->m_pMetadata->AddStatistics(inoutStats);
  7697. }
  7698. }
  7699. void BlockVector::AddDetailedStatistics(DetailedStatistics& inoutStats)
  7700. {
  7701. MutexLockRead lock(m_Mutex, m_hAllocator->UseMutex());
  7702. for (size_t i = 0; i < m_Blocks.size(); ++i)
  7703. {
  7704. const NormalBlock* const pBlock = m_Blocks[i];
  7705. D3D12MA_ASSERT(pBlock);
  7706. D3D12MA_HEAVY_ASSERT(pBlock->Validate());
  7707. pBlock->m_pMetadata->AddDetailedStatistics(inoutStats);
  7708. }
  7709. }
  7710. void BlockVector::WriteBlockInfoToJson(JsonWriter& json)
  7711. {
  7712. MutexLockRead lock(m_Mutex, m_hAllocator->UseMutex());
  7713. json.BeginObject();
  7714. for (size_t i = 0, count = m_Blocks.size(); i < count; ++i)
  7715. {
  7716. const NormalBlock* const pBlock = m_Blocks[i];
  7717. D3D12MA_ASSERT(pBlock);
  7718. D3D12MA_HEAVY_ASSERT(pBlock->Validate());
  7719. json.BeginString();
  7720. json.ContinueString(pBlock->GetId());
  7721. json.EndString();
  7722. json.BeginObject();
  7723. pBlock->m_pMetadata->WriteAllocationInfoToJson(json);
  7724. json.EndObject();
  7725. }
  7726. json.EndObject();
  7727. }
  7728. UINT64 BlockVector::CalcSumBlockSize() const
  7729. {
  7730. UINT64 result = 0;
  7731. for (size_t i = m_Blocks.size(); i--; )
  7732. {
  7733. result += m_Blocks[i]->m_pMetadata->GetSize();
  7734. }
  7735. return result;
  7736. }
  7737. UINT64 BlockVector::CalcMaxBlockSize() const
  7738. {
  7739. UINT64 result = 0;
  7740. for (size_t i = m_Blocks.size(); i--; )
  7741. {
  7742. result = D3D12MA_MAX(result, m_Blocks[i]->m_pMetadata->GetSize());
  7743. if (result >= m_PreferredBlockSize)
  7744. {
  7745. break;
  7746. }
  7747. }
  7748. return result;
  7749. }
  7750. void BlockVector::Remove(NormalBlock* pBlock)
  7751. {
  7752. for (size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
  7753. {
  7754. if (m_Blocks[blockIndex] == pBlock)
  7755. {
  7756. m_Blocks.remove(blockIndex);
  7757. return;
  7758. }
  7759. }
  7760. D3D12MA_ASSERT(0);
  7761. }
  7762. void BlockVector::IncrementallySortBlocks()
  7763. {
  7764. if (!m_IncrementalSort)
  7765. return;
  7766. // Bubble sort only until first swap.
  7767. for (size_t i = 1; i < m_Blocks.size(); ++i)
  7768. {
  7769. if (m_Blocks[i - 1]->m_pMetadata->GetSumFreeSize() > m_Blocks[i]->m_pMetadata->GetSumFreeSize())
  7770. {
  7771. D3D12MA_SWAP(m_Blocks[i - 1], m_Blocks[i]);
  7772. return;
  7773. }
  7774. }
  7775. }
  7776. void BlockVector::SortByFreeSize()
  7777. {
  7778. D3D12MA_SORT(m_Blocks.begin(), m_Blocks.end(),
  7779. [](auto* b1, auto* b2)
  7780. {
  7781. return b1->m_pMetadata->GetSumFreeSize() < b2->m_pMetadata->GetSumFreeSize();
  7782. });
  7783. }
  7784. HRESULT BlockVector::AllocatePage(
  7785. UINT64 size,
  7786. UINT64 alignment,
  7787. const ALLOCATION_DESC& allocDesc,
  7788. Allocation** pAllocation)
  7789. {
  7790. // Early reject: requested allocation size is larger that maximum block size for this block vector.
  7791. if (size + D3D12MA_DEBUG_MARGIN > m_PreferredBlockSize)
  7792. {
  7793. return E_OUTOFMEMORY;
  7794. }
  7795. UINT64 freeMemory = UINT64_MAX;
  7796. if (IsHeapTypeStandard(m_HeapProps.Type))
  7797. {
  7798. Budget budget = {};
  7799. m_hAllocator->GetBudgetForHeapType(budget, m_HeapProps.Type);
  7800. freeMemory = (budget.UsageBytes < budget.BudgetBytes) ? (budget.BudgetBytes - budget.UsageBytes) : 0;
  7801. }
  7802. const bool canCreateNewBlock =
  7803. ((allocDesc.Flags & ALLOCATION_FLAG_NEVER_ALLOCATE) == 0) &&
  7804. (m_Blocks.size() < m_MaxBlockCount) &&
  7805. // Even if we don't have to stay within budget with this allocation, when the
  7806. // budget would be exceeded, we don't want to allocate new blocks, but always
  7807. // create resources as committed.
  7808. freeMemory >= size;
  7809. // 1. Search existing allocations
  7810. {
  7811. // Forward order in m_Blocks - prefer blocks with smallest amount of free space.
  7812. for (size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
  7813. {
  7814. NormalBlock* const pCurrBlock = m_Blocks[blockIndex];
  7815. D3D12MA_ASSERT(pCurrBlock);
  7816. HRESULT hr = AllocateFromBlock(
  7817. pCurrBlock,
  7818. size,
  7819. alignment,
  7820. allocDesc.Flags,
  7821. allocDesc.pPrivateData,
  7822. allocDesc.Flags & ALLOCATION_FLAG_STRATEGY_MASK,
  7823. pAllocation);
  7824. if (SUCCEEDED(hr))
  7825. {
  7826. return hr;
  7827. }
  7828. }
  7829. }
  7830. // 2. Try to create new block.
  7831. if (canCreateNewBlock)
  7832. {
  7833. // Calculate optimal size for new block.
  7834. UINT64 newBlockSize = m_PreferredBlockSize;
  7835. UINT newBlockSizeShift = 0;
  7836. if (!m_ExplicitBlockSize)
  7837. {
  7838. // Allocate 1/8, 1/4, 1/2 as first blocks.
  7839. const UINT64 maxExistingBlockSize = CalcMaxBlockSize();
  7840. for (UINT i = 0; i < NEW_BLOCK_SIZE_SHIFT_MAX; ++i)
  7841. {
  7842. const UINT64 smallerNewBlockSize = newBlockSize / 2;
  7843. if (smallerNewBlockSize > maxExistingBlockSize && smallerNewBlockSize >= size * 2)
  7844. {
  7845. newBlockSize = smallerNewBlockSize;
  7846. ++newBlockSizeShift;
  7847. }
  7848. else
  7849. {
  7850. break;
  7851. }
  7852. }
  7853. }
  7854. size_t newBlockIndex = 0;
  7855. HRESULT hr = newBlockSize <= freeMemory ?
  7856. CreateBlock(newBlockSize, &newBlockIndex) : E_OUTOFMEMORY;
  7857. // Allocation of this size failed? Try 1/2, 1/4, 1/8 of m_PreferredBlockSize.
  7858. if (!m_ExplicitBlockSize)
  7859. {
  7860. while (FAILED(hr) && newBlockSizeShift < NEW_BLOCK_SIZE_SHIFT_MAX)
  7861. {
  7862. const UINT64 smallerNewBlockSize = newBlockSize / 2;
  7863. if (smallerNewBlockSize >= size)
  7864. {
  7865. newBlockSize = smallerNewBlockSize;
  7866. ++newBlockSizeShift;
  7867. hr = newBlockSize <= freeMemory ?
  7868. CreateBlock(newBlockSize, &newBlockIndex) : E_OUTOFMEMORY;
  7869. }
  7870. else
  7871. {
  7872. break;
  7873. }
  7874. }
  7875. }
  7876. if (SUCCEEDED(hr))
  7877. {
  7878. NormalBlock* const pBlock = m_Blocks[newBlockIndex];
  7879. D3D12MA_ASSERT(pBlock->m_pMetadata->GetSize() >= size);
  7880. hr = AllocateFromBlock(
  7881. pBlock,
  7882. size,
  7883. alignment,
  7884. allocDesc.Flags,
  7885. allocDesc.pPrivateData,
  7886. allocDesc.Flags & ALLOCATION_FLAG_STRATEGY_MASK,
  7887. pAllocation);
  7888. if (SUCCEEDED(hr))
  7889. {
  7890. return hr;
  7891. }
  7892. else
  7893. {
  7894. // Allocation from new block failed, possibly due to D3D12MA_DEBUG_MARGIN or alignment.
  7895. return E_OUTOFMEMORY;
  7896. }
  7897. }
  7898. }
  7899. return E_OUTOFMEMORY;
  7900. }
  7901. HRESULT BlockVector::AllocateFromBlock(
  7902. NormalBlock* pBlock,
  7903. UINT64 size,
  7904. UINT64 alignment,
  7905. ALLOCATION_FLAGS allocFlags,
  7906. void* pPrivateData,
  7907. UINT32 strategy,
  7908. Allocation** pAllocation)
  7909. {
  7910. alignment = D3D12MA_MAX(alignment, m_MinAllocationAlignment);
  7911. AllocationRequest currRequest = {};
  7912. if (pBlock->m_pMetadata->CreateAllocationRequest(
  7913. size,
  7914. alignment,
  7915. allocFlags & ALLOCATION_FLAG_UPPER_ADDRESS,
  7916. strategy,
  7917. &currRequest))
  7918. {
  7919. return CommitAllocationRequest(currRequest, pBlock, size, alignment, pPrivateData, pAllocation);
  7920. }
  7921. return E_OUTOFMEMORY;
  7922. }
  7923. HRESULT BlockVector::CommitAllocationRequest(
  7924. AllocationRequest& allocRequest,
  7925. NormalBlock* pBlock,
  7926. UINT64 size,
  7927. UINT64 alignment,
  7928. void* pPrivateData,
  7929. Allocation** pAllocation)
  7930. {
  7931. // We no longer have an empty Allocation.
  7932. if (pBlock->m_pMetadata->IsEmpty())
  7933. m_HasEmptyBlock = false;
  7934. *pAllocation = m_hAllocator->GetAllocationObjectAllocator().Allocate(m_hAllocator, size, alignment, allocRequest.zeroInitialized);
  7935. pBlock->m_pMetadata->Alloc(allocRequest, size, *pAllocation);
  7936. (*pAllocation)->InitPlaced(allocRequest.allocHandle, pBlock);
  7937. (*pAllocation)->SetPrivateData(pPrivateData);
  7938. D3D12MA_HEAVY_ASSERT(pBlock->Validate());
  7939. m_hAllocator->m_Budget.AddAllocation(m_hAllocator->HeapPropertiesToMemorySegmentGroup(m_HeapProps), size);
  7940. return S_OK;
  7941. }
  7942. HRESULT BlockVector::CreateBlock(
  7943. UINT64 blockSize,
  7944. size_t* pNewBlockIndex)
  7945. {
  7946. NormalBlock* const pBlock = D3D12MA_NEW(m_hAllocator->GetAllocs(), NormalBlock)(
  7947. m_hAllocator,
  7948. this,
  7949. m_HeapProps,
  7950. m_HeapFlags,
  7951. blockSize,
  7952. m_NextBlockId++);
  7953. HRESULT hr = pBlock->Init(m_Algorithm, m_ProtectedSession, m_DenyMsaaTextures);
  7954. if (FAILED(hr))
  7955. {
  7956. D3D12MA_DELETE(m_hAllocator->GetAllocs(), pBlock);
  7957. return hr;
  7958. }
  7959. m_hAllocator->SetResidencyPriority(pBlock->GetHeap(), m_ResidencyPriority);
  7960. m_Blocks.push_back(pBlock);
  7961. if (pNewBlockIndex != NULL)
  7962. {
  7963. *pNewBlockIndex = m_Blocks.size() - 1;
  7964. }
  7965. return hr;
  7966. }
  7967. #endif // _D3D12MA_BLOCK_VECTOR_FUNCTIONS
  7968. #ifndef _D3D12MA_DEFRAGMENTATION_CONTEXT_PIMPL_FUNCTIONS
  7969. DefragmentationContextPimpl::DefragmentationContextPimpl(
  7970. AllocatorPimpl* hAllocator,
  7971. const DEFRAGMENTATION_DESC& desc,
  7972. BlockVector* poolVector)
  7973. : m_MaxPassBytes(desc.MaxBytesPerPass == 0 ? UINT64_MAX : desc.MaxBytesPerPass),
  7974. m_MaxPassAllocations(desc.MaxAllocationsPerPass == 0 ? UINT32_MAX : desc.MaxAllocationsPerPass),
  7975. m_Moves(hAllocator->GetAllocs())
  7976. {
  7977. m_Algorithm = desc.Flags & DEFRAGMENTATION_FLAG_ALGORITHM_MASK;
  7978. if (poolVector != NULL)
  7979. {
  7980. m_BlockVectorCount = 1;
  7981. m_PoolBlockVector = poolVector;
  7982. m_pBlockVectors = &m_PoolBlockVector;
  7983. m_PoolBlockVector->SetIncrementalSort(false);
  7984. m_PoolBlockVector->SortByFreeSize();
  7985. }
  7986. else
  7987. {
  7988. m_BlockVectorCount = hAllocator->GetDefaultPoolCount();
  7989. m_PoolBlockVector = NULL;
  7990. m_pBlockVectors = hAllocator->GetDefaultPools();
  7991. for (UINT32 i = 0; i < m_BlockVectorCount; ++i)
  7992. {
  7993. BlockVector* vector = m_pBlockVectors[i];
  7994. if (vector != NULL)
  7995. {
  7996. vector->SetIncrementalSort(false);
  7997. vector->SortByFreeSize();
  7998. }
  7999. }
  8000. }
  8001. switch (m_Algorithm)
  8002. {
  8003. case 0: // Default algorithm
  8004. m_Algorithm = DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED;
  8005. case DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED:
  8006. {
  8007. m_AlgorithmState = D3D12MA_NEW_ARRAY(hAllocator->GetAllocs(), StateBalanced, m_BlockVectorCount);
  8008. break;
  8009. }
  8010. }
  8011. }
  8012. DefragmentationContextPimpl::~DefragmentationContextPimpl()
  8013. {
  8014. if (m_PoolBlockVector != NULL)
  8015. m_PoolBlockVector->SetIncrementalSort(true);
  8016. else
  8017. {
  8018. for (UINT32 i = 0; i < m_BlockVectorCount; ++i)
  8019. {
  8020. BlockVector* vector = m_pBlockVectors[i];
  8021. if (vector != NULL)
  8022. vector->SetIncrementalSort(true);
  8023. }
  8024. }
  8025. if (m_AlgorithmState)
  8026. {
  8027. switch (m_Algorithm)
  8028. {
  8029. case DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED:
  8030. D3D12MA_DELETE_ARRAY(m_Moves.GetAllocs(), reinterpret_cast<StateBalanced*>(m_AlgorithmState), m_BlockVectorCount);
  8031. break;
  8032. default:
  8033. D3D12MA_ASSERT(0);
  8034. }
  8035. }
  8036. }
  8037. HRESULT DefragmentationContextPimpl::DefragmentPassBegin(DEFRAGMENTATION_PASS_MOVE_INFO& moveInfo)
  8038. {
  8039. if (m_PoolBlockVector != NULL)
  8040. {
  8041. MutexLockWrite lock(m_PoolBlockVector->GetMutex(), m_PoolBlockVector->m_hAllocator->UseMutex());
  8042. if (m_PoolBlockVector->GetBlockCount() > 1)
  8043. ComputeDefragmentation(*m_PoolBlockVector, 0);
  8044. else if (m_PoolBlockVector->GetBlockCount() == 1)
  8045. ReallocWithinBlock(*m_PoolBlockVector, m_PoolBlockVector->GetBlock(0));
  8046. // Setup index into block vector
  8047. for (size_t i = 0; i < m_Moves.size(); ++i)
  8048. m_Moves[i].pDstTmpAllocation->SetPrivateData(0);
  8049. }
  8050. else
  8051. {
  8052. for (UINT32 i = 0; i < m_BlockVectorCount; ++i)
  8053. {
  8054. if (m_pBlockVectors[i] != NULL)
  8055. {
  8056. MutexLockWrite lock(m_pBlockVectors[i]->GetMutex(), m_pBlockVectors[i]->m_hAllocator->UseMutex());
  8057. bool end = false;
  8058. size_t movesOffset = m_Moves.size();
  8059. if (m_pBlockVectors[i]->GetBlockCount() > 1)
  8060. {
  8061. end = ComputeDefragmentation(*m_pBlockVectors[i], i);
  8062. }
  8063. else if (m_pBlockVectors[i]->GetBlockCount() == 1)
  8064. {
  8065. end = ReallocWithinBlock(*m_pBlockVectors[i], m_pBlockVectors[i]->GetBlock(0));
  8066. }
  8067. // Setup index into block vector
  8068. for (; movesOffset < m_Moves.size(); ++movesOffset)
  8069. m_Moves[movesOffset].pDstTmpAllocation->SetPrivateData(reinterpret_cast<void*>(static_cast<uintptr_t>(i)));
  8070. if (end)
  8071. break;
  8072. }
  8073. }
  8074. }
  8075. moveInfo.MoveCount = static_cast<UINT32>(m_Moves.size());
  8076. if (moveInfo.MoveCount > 0)
  8077. {
  8078. moveInfo.pMoves = m_Moves.data();
  8079. return S_FALSE;
  8080. }
  8081. moveInfo.pMoves = NULL;
  8082. return S_OK;
  8083. }
  8084. HRESULT DefragmentationContextPimpl::DefragmentPassEnd(DEFRAGMENTATION_PASS_MOVE_INFO& moveInfo)
  8085. {
  8086. D3D12MA_ASSERT(moveInfo.MoveCount > 0 ? moveInfo.pMoves != NULL : true);
  8087. HRESULT result = S_OK;
  8088. Vector<FragmentedBlock> immovableBlocks(m_Moves.GetAllocs());
  8089. for (uint32_t i = 0; i < moveInfo.MoveCount; ++i)
  8090. {
  8091. DEFRAGMENTATION_MOVE& move = moveInfo.pMoves[i];
  8092. size_t prevCount = 0, currentCount = 0;
  8093. UINT64 freedBlockSize = 0;
  8094. UINT32 vectorIndex;
  8095. BlockVector* vector;
  8096. if (m_PoolBlockVector != NULL)
  8097. {
  8098. vectorIndex = 0;
  8099. vector = m_PoolBlockVector;
  8100. }
  8101. else
  8102. {
  8103. vectorIndex = static_cast<UINT32>(reinterpret_cast<uintptr_t>(move.pDstTmpAllocation->GetPrivateData()));
  8104. vector = m_pBlockVectors[vectorIndex];
  8105. D3D12MA_ASSERT(vector != NULL);
  8106. }
  8107. switch (move.Operation)
  8108. {
  8109. case DEFRAGMENTATION_MOVE_OPERATION_COPY:
  8110. {
  8111. move.pSrcAllocation->SwapBlockAllocation(move.pDstTmpAllocation);
  8112. // Scope for locks, Free have it's own lock
  8113. {
  8114. MutexLockRead lock(vector->GetMutex(), vector->m_hAllocator->UseMutex());
  8115. prevCount = vector->GetBlockCount();
  8116. freedBlockSize = move.pDstTmpAllocation->GetBlock()->m_pMetadata->GetSize();
  8117. }
  8118. move.pDstTmpAllocation->Release();
  8119. {
  8120. MutexLockRead lock(vector->GetMutex(), vector->m_hAllocator->UseMutex());
  8121. currentCount = vector->GetBlockCount();
  8122. }
  8123. result = S_FALSE;
  8124. break;
  8125. }
  8126. case DEFRAGMENTATION_MOVE_OPERATION_IGNORE:
  8127. {
  8128. m_PassStats.BytesMoved -= move.pSrcAllocation->GetSize();
  8129. --m_PassStats.AllocationsMoved;
  8130. move.pDstTmpAllocation->Release();
  8131. NormalBlock* newBlock = move.pSrcAllocation->GetBlock();
  8132. bool notPresent = true;
  8133. for (const FragmentedBlock& block : immovableBlocks)
  8134. {
  8135. if (block.block == newBlock)
  8136. {
  8137. notPresent = false;
  8138. break;
  8139. }
  8140. }
  8141. if (notPresent)
  8142. immovableBlocks.push_back({ vectorIndex, newBlock });
  8143. break;
  8144. }
  8145. case DEFRAGMENTATION_MOVE_OPERATION_DESTROY:
  8146. {
  8147. m_PassStats.BytesMoved -= move.pSrcAllocation->GetSize();
  8148. --m_PassStats.AllocationsMoved;
  8149. // Scope for locks, Free have it's own lock
  8150. {
  8151. MutexLockRead lock(vector->GetMutex(), vector->m_hAllocator->UseMutex());
  8152. prevCount = vector->GetBlockCount();
  8153. freedBlockSize = move.pSrcAllocation->GetBlock()->m_pMetadata->GetSize();
  8154. }
  8155. move.pSrcAllocation->Release();
  8156. {
  8157. MutexLockRead lock(vector->GetMutex(), vector->m_hAllocator->UseMutex());
  8158. currentCount = vector->GetBlockCount();
  8159. }
  8160. freedBlockSize *= prevCount - currentCount;
  8161. UINT64 dstBlockSize;
  8162. {
  8163. MutexLockRead lock(vector->GetMutex(), vector->m_hAllocator->UseMutex());
  8164. dstBlockSize = move.pDstTmpAllocation->GetBlock()->m_pMetadata->GetSize();
  8165. }
  8166. move.pDstTmpAllocation->Release();
  8167. {
  8168. MutexLockRead lock(vector->GetMutex(), vector->m_hAllocator->UseMutex());
  8169. freedBlockSize += dstBlockSize * (currentCount - vector->GetBlockCount());
  8170. currentCount = vector->GetBlockCount();
  8171. }
  8172. result = S_FALSE;
  8173. break;
  8174. }
  8175. default:
  8176. D3D12MA_ASSERT(0);
  8177. }
  8178. if (prevCount > currentCount)
  8179. {
  8180. size_t freedBlocks = prevCount - currentCount;
  8181. m_PassStats.HeapsFreed += static_cast<UINT32>(freedBlocks);
  8182. m_PassStats.BytesFreed += freedBlockSize;
  8183. }
  8184. }
  8185. moveInfo.MoveCount = 0;
  8186. moveInfo.pMoves = NULL;
  8187. m_Moves.clear();
  8188. // Update stats
  8189. m_GlobalStats.AllocationsMoved += m_PassStats.AllocationsMoved;
  8190. m_GlobalStats.BytesFreed += m_PassStats.BytesFreed;
  8191. m_GlobalStats.BytesMoved += m_PassStats.BytesMoved;
  8192. m_GlobalStats.HeapsFreed += m_PassStats.HeapsFreed;
  8193. m_PassStats = { 0 };
  8194. // Move blocks with immovable allocations according to algorithm
  8195. if (immovableBlocks.size() > 0)
  8196. {
  8197. // Move to the begining
  8198. for (const FragmentedBlock& block : immovableBlocks)
  8199. {
  8200. BlockVector* vector = m_pBlockVectors[block.data];
  8201. MutexLockWrite lock(vector->GetMutex(), vector->m_hAllocator->UseMutex());
  8202. for (size_t i = m_ImmovableBlockCount; i < vector->GetBlockCount(); ++i)
  8203. {
  8204. if (vector->GetBlock(i) == block.block)
  8205. {
  8206. D3D12MA_SWAP(vector->m_Blocks[i], vector->m_Blocks[m_ImmovableBlockCount++]);
  8207. break;
  8208. }
  8209. }
  8210. }
  8211. }
  8212. return result;
  8213. }
  8214. bool DefragmentationContextPimpl::ComputeDefragmentation(BlockVector& vector, size_t index)
  8215. {
  8216. switch (m_Algorithm)
  8217. {
  8218. case DEFRAGMENTATION_FLAG_ALGORITHM_FAST:
  8219. return ComputeDefragmentation_Fast(vector);
  8220. default:
  8221. D3D12MA_ASSERT(0);
  8222. case DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED:
  8223. return ComputeDefragmentation_Balanced(vector, index, true);
  8224. case DEFRAGMENTATION_FLAG_ALGORITHM_FULL:
  8225. return ComputeDefragmentation_Full(vector);
  8226. }
  8227. }
  8228. DefragmentationContextPimpl::MoveAllocationData DefragmentationContextPimpl::GetMoveData(
  8229. AllocHandle handle, BlockMetadata* metadata)
  8230. {
  8231. MoveAllocationData moveData;
  8232. moveData.move.pSrcAllocation = (Allocation*)metadata->GetAllocationPrivateData(handle);
  8233. moveData.size = moveData.move.pSrcAllocation->GetSize();
  8234. moveData.alignment = moveData.move.pSrcAllocation->GetAlignment();
  8235. moveData.flags = ALLOCATION_FLAG_NONE;
  8236. return moveData;
  8237. }
  8238. DefragmentationContextPimpl::CounterStatus DefragmentationContextPimpl::CheckCounters(UINT64 bytes)
  8239. {
  8240. // Ignore allocation if will exceed max size for copy
  8241. if (m_PassStats.BytesMoved + bytes > m_MaxPassBytes)
  8242. {
  8243. if (++m_IgnoredAllocs < MAX_ALLOCS_TO_IGNORE)
  8244. return CounterStatus::Ignore;
  8245. else
  8246. return CounterStatus::End;
  8247. }
  8248. return CounterStatus::Pass;
  8249. }
  8250. bool DefragmentationContextPimpl::IncrementCounters(UINT64 bytes)
  8251. {
  8252. m_PassStats.BytesMoved += bytes;
  8253. // Early return when max found
  8254. if (++m_PassStats.AllocationsMoved >= m_MaxPassAllocations || m_PassStats.BytesMoved >= m_MaxPassBytes)
  8255. {
  8256. D3D12MA_ASSERT((m_PassStats.AllocationsMoved == m_MaxPassAllocations ||
  8257. m_PassStats.BytesMoved == m_MaxPassBytes) && "Exceeded maximal pass threshold!");
  8258. return true;
  8259. }
  8260. return false;
  8261. }
  8262. bool DefragmentationContextPimpl::ReallocWithinBlock(BlockVector& vector, NormalBlock* block)
  8263. {
  8264. BlockMetadata* metadata = block->m_pMetadata;
  8265. for (AllocHandle handle = metadata->GetAllocationListBegin();
  8266. handle != (AllocHandle)0;
  8267. handle = metadata->GetNextAllocation(handle))
  8268. {
  8269. MoveAllocationData moveData = GetMoveData(handle, metadata);
  8270. // Ignore newly created allocations by defragmentation algorithm
  8271. if (moveData.move.pSrcAllocation->GetPrivateData() == this)
  8272. continue;
  8273. switch (CheckCounters(moveData.move.pSrcAllocation->GetSize()))
  8274. {
  8275. case CounterStatus::Ignore:
  8276. continue;
  8277. case CounterStatus::End:
  8278. return true;
  8279. default:
  8280. D3D12MA_ASSERT(0);
  8281. case CounterStatus::Pass:
  8282. break;
  8283. }
  8284. UINT64 offset = moveData.move.pSrcAllocation->GetOffset();
  8285. if (offset != 0 && metadata->GetSumFreeSize() >= moveData.size)
  8286. {
  8287. AllocationRequest request = {};
  8288. if (metadata->CreateAllocationRequest(
  8289. moveData.size,
  8290. moveData.alignment,
  8291. false,
  8292. ALLOCATION_FLAG_STRATEGY_MIN_OFFSET,
  8293. &request))
  8294. {
  8295. if (metadata->GetAllocationOffset(request.allocHandle) < offset)
  8296. {
  8297. if (SUCCEEDED(vector.CommitAllocationRequest(
  8298. request,
  8299. block,
  8300. moveData.size,
  8301. moveData.alignment,
  8302. this,
  8303. &moveData.move.pDstTmpAllocation)))
  8304. {
  8305. m_Moves.push_back(moveData.move);
  8306. if (IncrementCounters(moveData.size))
  8307. return true;
  8308. }
  8309. }
  8310. }
  8311. }
  8312. }
  8313. return false;
  8314. }
  8315. bool DefragmentationContextPimpl::AllocInOtherBlock(size_t start, size_t end, MoveAllocationData& data, BlockVector& vector)
  8316. {
  8317. for (; start < end; ++start)
  8318. {
  8319. NormalBlock* dstBlock = vector.GetBlock(start);
  8320. if (dstBlock->m_pMetadata->GetSumFreeSize() >= data.size)
  8321. {
  8322. if (SUCCEEDED(vector.AllocateFromBlock(dstBlock,
  8323. data.size,
  8324. data.alignment,
  8325. data.flags,
  8326. this,
  8327. 0,
  8328. &data.move.pDstTmpAllocation)))
  8329. {
  8330. m_Moves.push_back(data.move);
  8331. if (IncrementCounters(data.size))
  8332. return true;
  8333. break;
  8334. }
  8335. }
  8336. }
  8337. return false;
  8338. }
  8339. bool DefragmentationContextPimpl::ComputeDefragmentation_Fast(BlockVector& vector)
  8340. {
  8341. // Move only between blocks
  8342. // Go through allocations in last blocks and try to fit them inside first ones
  8343. for (size_t i = vector.GetBlockCount() - 1; i > m_ImmovableBlockCount; --i)
  8344. {
  8345. BlockMetadata* metadata = vector.GetBlock(i)->m_pMetadata;
  8346. for (AllocHandle handle = metadata->GetAllocationListBegin();
  8347. handle != (AllocHandle)0;
  8348. handle = metadata->GetNextAllocation(handle))
  8349. {
  8350. MoveAllocationData moveData = GetMoveData(handle, metadata);
  8351. // Ignore newly created allocations by defragmentation algorithm
  8352. if (moveData.move.pSrcAllocation->GetPrivateData() == this)
  8353. continue;
  8354. switch (CheckCounters(moveData.move.pSrcAllocation->GetSize()))
  8355. {
  8356. case CounterStatus::Ignore:
  8357. continue;
  8358. case CounterStatus::End:
  8359. return true;
  8360. default:
  8361. D3D12MA_ASSERT(0);
  8362. case CounterStatus::Pass:
  8363. break;
  8364. }
  8365. // Check all previous blocks for free space
  8366. if (AllocInOtherBlock(0, i, moveData, vector))
  8367. return true;
  8368. }
  8369. }
  8370. return false;
  8371. }
  8372. bool DefragmentationContextPimpl::ComputeDefragmentation_Balanced(BlockVector& vector, size_t index, bool update)
  8373. {
  8374. // Go over every allocation and try to fit it in previous blocks at lowest offsets,
  8375. // if not possible: realloc within single block to minimize offset (exclude offset == 0),
  8376. // but only if there are noticable gaps between them (some heuristic, ex. average size of allocation in block)
  8377. D3D12MA_ASSERT(m_AlgorithmState != NULL);
  8378. StateBalanced& vectorState = reinterpret_cast<StateBalanced*>(m_AlgorithmState)[index];
  8379. if (update && vectorState.avgAllocSize == UINT64_MAX)
  8380. UpdateVectorStatistics(vector, vectorState);
  8381. const size_t startMoveCount = m_Moves.size();
  8382. UINT64 minimalFreeRegion = vectorState.avgFreeSize / 2;
  8383. for (size_t i = vector.GetBlockCount() - 1; i > m_ImmovableBlockCount; --i)
  8384. {
  8385. NormalBlock* block = vector.GetBlock(i);
  8386. BlockMetadata* metadata = block->m_pMetadata;
  8387. UINT64 prevFreeRegionSize = 0;
  8388. for (AllocHandle handle = metadata->GetAllocationListBegin();
  8389. handle != (AllocHandle)0;
  8390. handle = metadata->GetNextAllocation(handle))
  8391. {
  8392. MoveAllocationData moveData = GetMoveData(handle, metadata);
  8393. // Ignore newly created allocations by defragmentation algorithm
  8394. if (moveData.move.pSrcAllocation->GetPrivateData() == this)
  8395. continue;
  8396. switch (CheckCounters(moveData.move.pSrcAllocation->GetSize()))
  8397. {
  8398. case CounterStatus::Ignore:
  8399. continue;
  8400. case CounterStatus::End:
  8401. return true;
  8402. default:
  8403. D3D12MA_ASSERT(0);
  8404. case CounterStatus::Pass:
  8405. break;
  8406. }
  8407. // Check all previous blocks for free space
  8408. const size_t prevMoveCount = m_Moves.size();
  8409. if (AllocInOtherBlock(0, i, moveData, vector))
  8410. return true;
  8411. UINT64 nextFreeRegionSize = metadata->GetNextFreeRegionSize(handle);
  8412. // If no room found then realloc within block for lower offset
  8413. UINT64 offset = moveData.move.pSrcAllocation->GetOffset();
  8414. if (prevMoveCount == m_Moves.size() && offset != 0 && metadata->GetSumFreeSize() >= moveData.size)
  8415. {
  8416. // Check if realloc will make sense
  8417. if (prevFreeRegionSize >= minimalFreeRegion ||
  8418. nextFreeRegionSize >= minimalFreeRegion ||
  8419. moveData.size <= vectorState.avgFreeSize ||
  8420. moveData.size <= vectorState.avgAllocSize)
  8421. {
  8422. AllocationRequest request = {};
  8423. if (metadata->CreateAllocationRequest(
  8424. moveData.size,
  8425. moveData.alignment,
  8426. false,
  8427. ALLOCATION_FLAG_STRATEGY_MIN_OFFSET,
  8428. &request))
  8429. {
  8430. if (metadata->GetAllocationOffset(request.allocHandle) < offset)
  8431. {
  8432. if (SUCCEEDED(vector.CommitAllocationRequest(
  8433. request,
  8434. block,
  8435. moveData.size,
  8436. moveData.alignment,
  8437. this,
  8438. &moveData.move.pDstTmpAllocation)))
  8439. {
  8440. m_Moves.push_back(moveData.move);
  8441. if (IncrementCounters(moveData.size))
  8442. return true;
  8443. }
  8444. }
  8445. }
  8446. }
  8447. }
  8448. prevFreeRegionSize = nextFreeRegionSize;
  8449. }
  8450. }
  8451. // No moves perfomed, update statistics to current vector state
  8452. if (startMoveCount == m_Moves.size() && !update)
  8453. {
  8454. vectorState.avgAllocSize = UINT64_MAX;
  8455. return ComputeDefragmentation_Balanced(vector, index, false);
  8456. }
  8457. return false;
  8458. }
  8459. bool DefragmentationContextPimpl::ComputeDefragmentation_Full(BlockVector& vector)
  8460. {
  8461. // Go over every allocation and try to fit it in previous blocks at lowest offsets,
  8462. // if not possible: realloc within single block to minimize offset (exclude offset == 0)
  8463. for (size_t i = vector.GetBlockCount() - 1; i > m_ImmovableBlockCount; --i)
  8464. {
  8465. NormalBlock* block = vector.GetBlock(i);
  8466. BlockMetadata* metadata = block->m_pMetadata;
  8467. for (AllocHandle handle = metadata->GetAllocationListBegin();
  8468. handle != (AllocHandle)0;
  8469. handle = metadata->GetNextAllocation(handle))
  8470. {
  8471. MoveAllocationData moveData = GetMoveData(handle, metadata);
  8472. // Ignore newly created allocations by defragmentation algorithm
  8473. if (moveData.move.pSrcAllocation->GetPrivateData() == this)
  8474. continue;
  8475. switch (CheckCounters(moveData.move.pSrcAllocation->GetSize()))
  8476. {
  8477. case CounterStatus::Ignore:
  8478. continue;
  8479. case CounterStatus::End:
  8480. return true;
  8481. default:
  8482. D3D12MA_ASSERT(0);
  8483. case CounterStatus::Pass:
  8484. break;
  8485. }
  8486. // Check all previous blocks for free space
  8487. const size_t prevMoveCount = m_Moves.size();
  8488. if (AllocInOtherBlock(0, i, moveData, vector))
  8489. return true;
  8490. // If no room found then realloc within block for lower offset
  8491. UINT64 offset = moveData.move.pSrcAllocation->GetOffset();
  8492. if (prevMoveCount == m_Moves.size() && offset != 0 && metadata->GetSumFreeSize() >= moveData.size)
  8493. {
  8494. AllocationRequest request = {};
  8495. if (metadata->CreateAllocationRequest(
  8496. moveData.size,
  8497. moveData.alignment,
  8498. false,
  8499. ALLOCATION_FLAG_STRATEGY_MIN_OFFSET,
  8500. &request))
  8501. {
  8502. if (metadata->GetAllocationOffset(request.allocHandle) < offset)
  8503. {
  8504. if (SUCCEEDED(vector.CommitAllocationRequest(
  8505. request,
  8506. block,
  8507. moveData.size,
  8508. moveData.alignment,
  8509. this,
  8510. &moveData.move.pDstTmpAllocation)))
  8511. {
  8512. m_Moves.push_back(moveData.move);
  8513. if (IncrementCounters(moveData.size))
  8514. return true;
  8515. }
  8516. }
  8517. }
  8518. }
  8519. }
  8520. }
  8521. return false;
  8522. }
  8523. void DefragmentationContextPimpl::UpdateVectorStatistics(BlockVector& vector, StateBalanced& state)
  8524. {
  8525. size_t allocCount = 0;
  8526. size_t freeCount = 0;
  8527. state.avgFreeSize = 0;
  8528. state.avgAllocSize = 0;
  8529. for (size_t i = 0; i < vector.GetBlockCount(); ++i)
  8530. {
  8531. BlockMetadata* metadata = vector.GetBlock(i)->m_pMetadata;
  8532. allocCount += metadata->GetAllocationCount();
  8533. freeCount += metadata->GetFreeRegionsCount();
  8534. state.avgFreeSize += metadata->GetSumFreeSize();
  8535. state.avgAllocSize += metadata->GetSize();
  8536. }
  8537. state.avgAllocSize = (state.avgAllocSize - state.avgFreeSize) / allocCount;
  8538. state.avgFreeSize /= freeCount;
  8539. }
  8540. #endif // _D3D12MA_DEFRAGMENTATION_CONTEXT_PIMPL_FUNCTIONS
  8541. #ifndef _D3D12MA_POOL_PIMPL_FUNCTIONS
  8542. PoolPimpl::PoolPimpl(AllocatorPimpl* allocator, const POOL_DESC& desc)
  8543. : m_Allocator(allocator),
  8544. m_Desc(desc),
  8545. m_BlockVector(NULL),
  8546. m_Name(NULL)
  8547. {
  8548. const bool explicitBlockSize = desc.BlockSize != 0;
  8549. const UINT64 preferredBlockSize = explicitBlockSize ? desc.BlockSize : D3D12MA_DEFAULT_BLOCK_SIZE;
  8550. UINT maxBlockCount = desc.MaxBlockCount != 0 ? desc.MaxBlockCount : UINT_MAX;
  8551. #ifndef __ID3D12Device4_INTERFACE_DEFINED__
  8552. D3D12MA_ASSERT(m_Desc.pProtectedSession == NULL);
  8553. #endif
  8554. m_BlockVector = D3D12MA_NEW(allocator->GetAllocs(), BlockVector)(
  8555. allocator, desc.HeapProperties, desc.HeapFlags,
  8556. preferredBlockSize,
  8557. desc.MinBlockCount, maxBlockCount,
  8558. explicitBlockSize,
  8559. D3D12MA_MAX(desc.MinAllocationAlignment, (UINT64)D3D12MA_DEBUG_ALIGNMENT),
  8560. (desc.Flags & POOL_FLAG_ALGORITHM_MASK) != 0,
  8561. (desc.Flags & POOL_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED) != 0,
  8562. desc.pProtectedSession,
  8563. desc.ResidencyPriority);
  8564. }
  8565. PoolPimpl::~PoolPimpl()
  8566. {
  8567. D3D12MA_ASSERT(m_PrevPool == NULL && m_NextPool == NULL);
  8568. FreeName();
  8569. D3D12MA_DELETE(m_Allocator->GetAllocs(), m_BlockVector);
  8570. }
  8571. HRESULT PoolPimpl::Init()
  8572. {
  8573. m_CommittedAllocations.Init(m_Allocator->UseMutex(), m_Desc.HeapProperties.Type, this);
  8574. return m_BlockVector->CreateMinBlocks();
  8575. }
  8576. void PoolPimpl::GetStatistics(Statistics& outStats)
  8577. {
  8578. ClearStatistics(outStats);
  8579. m_BlockVector->AddStatistics(outStats);
  8580. m_CommittedAllocations.AddStatistics(outStats);
  8581. }
  8582. void PoolPimpl::CalculateStatistics(DetailedStatistics& outStats)
  8583. {
  8584. ClearDetailedStatistics(outStats);
  8585. AddDetailedStatistics(outStats);
  8586. }
  8587. void PoolPimpl::AddDetailedStatistics(DetailedStatistics& inoutStats)
  8588. {
  8589. m_BlockVector->AddDetailedStatistics(inoutStats);
  8590. m_CommittedAllocations.AddDetailedStatistics(inoutStats);
  8591. }
  8592. void PoolPimpl::SetName(LPCWSTR Name)
  8593. {
  8594. FreeName();
  8595. if (Name)
  8596. {
  8597. const size_t nameCharCount = wcslen(Name) + 1;
  8598. m_Name = D3D12MA_NEW_ARRAY(m_Allocator->GetAllocs(), WCHAR, nameCharCount);
  8599. memcpy(m_Name, Name, nameCharCount * sizeof(WCHAR));
  8600. }
  8601. }
  8602. void PoolPimpl::FreeName()
  8603. {
  8604. if (m_Name)
  8605. {
  8606. const size_t nameCharCount = wcslen(m_Name) + 1;
  8607. D3D12MA_DELETE_ARRAY(m_Allocator->GetAllocs(), m_Name, nameCharCount);
  8608. m_Name = NULL;
  8609. }
  8610. }
  8611. #endif // _D3D12MA_POOL_PIMPL_FUNCTIONS
  8612. #ifndef _D3D12MA_PUBLIC_INTERFACE
  8613. HRESULT CreateAllocator(const ALLOCATOR_DESC* pDesc, Allocator** ppAllocator)
  8614. {
  8615. if (!pDesc || !ppAllocator || !pDesc->pDevice || !pDesc->pAdapter ||
  8616. !(pDesc->PreferredBlockSize == 0 || (pDesc->PreferredBlockSize >= 16 && pDesc->PreferredBlockSize < 0x10000000000ull)))
  8617. {
  8618. D3D12MA_ASSERT(0 && "Invalid arguments passed to CreateAllocator.");
  8619. return E_INVALIDARG;
  8620. }
  8621. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  8622. ALLOCATION_CALLBACKS allocationCallbacks;
  8623. SetupAllocationCallbacks(allocationCallbacks, pDesc->pAllocationCallbacks);
  8624. *ppAllocator = D3D12MA_NEW(allocationCallbacks, Allocator)(allocationCallbacks, *pDesc);
  8625. HRESULT hr = (*ppAllocator)->m_Pimpl->Init(*pDesc);
  8626. if (FAILED(hr))
  8627. {
  8628. D3D12MA_DELETE(allocationCallbacks, *ppAllocator);
  8629. *ppAllocator = NULL;
  8630. }
  8631. return hr;
  8632. }
  8633. HRESULT CreateVirtualBlock(const VIRTUAL_BLOCK_DESC* pDesc, VirtualBlock** ppVirtualBlock)
  8634. {
  8635. if (!pDesc || !ppVirtualBlock)
  8636. {
  8637. D3D12MA_ASSERT(0 && "Invalid arguments passed to CreateVirtualBlock.");
  8638. return E_INVALIDARG;
  8639. }
  8640. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  8641. ALLOCATION_CALLBACKS allocationCallbacks;
  8642. SetupAllocationCallbacks(allocationCallbacks, pDesc->pAllocationCallbacks);
  8643. *ppVirtualBlock = D3D12MA_NEW(allocationCallbacks, VirtualBlock)(allocationCallbacks, *pDesc);
  8644. return S_OK;
  8645. }
  8646. #ifndef _D3D12MA_IUNKNOWN_IMPL_FUNCTIONS
  8647. HRESULT STDMETHODCALLTYPE IUnknownImpl::QueryInterface(REFIID riid, void** ppvObject)
  8648. {
  8649. if (ppvObject == NULL)
  8650. return E_POINTER;
  8651. if (riid == IID_IUnknown)
  8652. {
  8653. ++m_RefCount;
  8654. *ppvObject = this;
  8655. return S_OK;
  8656. }
  8657. *ppvObject = NULL;
  8658. return E_NOINTERFACE;
  8659. }
  8660. ULONG STDMETHODCALLTYPE IUnknownImpl::AddRef()
  8661. {
  8662. return ++m_RefCount;
  8663. }
  8664. ULONG STDMETHODCALLTYPE IUnknownImpl::Release()
  8665. {
  8666. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  8667. const uint32_t newRefCount = --m_RefCount;
  8668. if (newRefCount == 0)
  8669. ReleaseThis();
  8670. return newRefCount;
  8671. }
  8672. #endif // _D3D12MA_IUNKNOWN_IMPL_FUNCTIONS
  8673. #ifndef _D3D12MA_ALLOCATION_FUNCTIONS
  8674. void Allocation::PackedData::SetType(Type type)
  8675. {
  8676. const UINT u = (UINT)type;
  8677. D3D12MA_ASSERT(u < (1u << 2));
  8678. m_Type = u;
  8679. }
  8680. void Allocation::PackedData::SetResourceDimension(D3D12_RESOURCE_DIMENSION resourceDimension)
  8681. {
  8682. const UINT u = (UINT)resourceDimension;
  8683. D3D12MA_ASSERT(u < (1u << 3));
  8684. m_ResourceDimension = u;
  8685. }
  8686. void Allocation::PackedData::SetResourceFlags(D3D12_RESOURCE_FLAGS resourceFlags)
  8687. {
  8688. const UINT u = (UINT)resourceFlags;
  8689. D3D12MA_ASSERT(u < (1u << 24));
  8690. m_ResourceFlags = u;
  8691. }
  8692. void Allocation::PackedData::SetTextureLayout(D3D12_TEXTURE_LAYOUT textureLayout)
  8693. {
  8694. const UINT u = (UINT)textureLayout;
  8695. D3D12MA_ASSERT(u < (1u << 9));
  8696. m_TextureLayout = u;
  8697. }
  8698. UINT64 Allocation::GetOffset() const
  8699. {
  8700. switch (m_PackedData.GetType())
  8701. {
  8702. case TYPE_COMMITTED:
  8703. case TYPE_HEAP:
  8704. return 0;
  8705. case TYPE_PLACED:
  8706. return m_Placed.block->m_pMetadata->GetAllocationOffset(m_Placed.allocHandle);
  8707. default:
  8708. D3D12MA_ASSERT(0);
  8709. return 0;
  8710. }
  8711. }
  8712. void Allocation::SetResource(ID3D12Resource* pResource)
  8713. {
  8714. if (pResource != m_Resource)
  8715. {
  8716. if (m_Resource)
  8717. m_Resource->Release();
  8718. m_Resource = pResource;
  8719. if (m_Resource)
  8720. m_Resource->AddRef();
  8721. }
  8722. }
  8723. ID3D12Heap* Allocation::GetHeap() const
  8724. {
  8725. switch (m_PackedData.GetType())
  8726. {
  8727. case TYPE_COMMITTED:
  8728. return NULL;
  8729. case TYPE_PLACED:
  8730. return m_Placed.block->GetHeap();
  8731. case TYPE_HEAP:
  8732. return m_Heap.heap;
  8733. default:
  8734. D3D12MA_ASSERT(0);
  8735. return 0;
  8736. }
  8737. }
  8738. void Allocation::SetName(LPCWSTR Name)
  8739. {
  8740. FreeName();
  8741. if (Name)
  8742. {
  8743. const size_t nameCharCount = wcslen(Name) + 1;
  8744. m_Name = D3D12MA_NEW_ARRAY(m_Allocator->GetAllocs(), WCHAR, nameCharCount);
  8745. memcpy(m_Name, Name, nameCharCount * sizeof(WCHAR));
  8746. }
  8747. }
  8748. void Allocation::ReleaseThis()
  8749. {
  8750. if (this == NULL)
  8751. {
  8752. return;
  8753. }
  8754. SAFE_RELEASE(m_Resource);
  8755. switch (m_PackedData.GetType())
  8756. {
  8757. case TYPE_COMMITTED:
  8758. m_Allocator->FreeCommittedMemory(this);
  8759. break;
  8760. case TYPE_PLACED:
  8761. m_Allocator->FreePlacedMemory(this);
  8762. break;
  8763. case TYPE_HEAP:
  8764. m_Allocator->FreeHeapMemory(this);
  8765. break;
  8766. }
  8767. FreeName();
  8768. m_Allocator->GetAllocationObjectAllocator().Free(this);
  8769. }
  8770. Allocation::Allocation(AllocatorPimpl* allocator, UINT64 size, UINT64 alignment, BOOL wasZeroInitialized)
  8771. : m_Allocator{ allocator },
  8772. m_Size{ size },
  8773. m_Alignment{ alignment },
  8774. m_Resource{ NULL },
  8775. m_pPrivateData{ NULL },
  8776. m_Name{ NULL }
  8777. {
  8778. D3D12MA_ASSERT(allocator);
  8779. m_PackedData.SetType(TYPE_COUNT);
  8780. m_PackedData.SetResourceDimension(D3D12_RESOURCE_DIMENSION_UNKNOWN);
  8781. m_PackedData.SetResourceFlags(D3D12_RESOURCE_FLAG_NONE);
  8782. m_PackedData.SetTextureLayout(D3D12_TEXTURE_LAYOUT_UNKNOWN);
  8783. m_PackedData.SetWasZeroInitialized(wasZeroInitialized);
  8784. }
  8785. void Allocation::InitCommitted(CommittedAllocationList* list)
  8786. {
  8787. m_PackedData.SetType(TYPE_COMMITTED);
  8788. m_Committed.list = list;
  8789. m_Committed.prev = NULL;
  8790. m_Committed.next = NULL;
  8791. }
  8792. void Allocation::InitPlaced(AllocHandle allocHandle, NormalBlock* block)
  8793. {
  8794. m_PackedData.SetType(TYPE_PLACED);
  8795. m_Placed.allocHandle = allocHandle;
  8796. m_Placed.block = block;
  8797. }
  8798. void Allocation::InitHeap(CommittedAllocationList* list, ID3D12Heap* heap)
  8799. {
  8800. m_PackedData.SetType(TYPE_HEAP);
  8801. m_Heap.list = list;
  8802. m_Committed.prev = NULL;
  8803. m_Committed.next = NULL;
  8804. m_Heap.heap = heap;
  8805. }
  8806. void Allocation::SwapBlockAllocation(Allocation* allocation)
  8807. {
  8808. D3D12MA_ASSERT(allocation != NULL);
  8809. D3D12MA_ASSERT(m_PackedData.GetType() == TYPE_PLACED);
  8810. D3D12MA_ASSERT(allocation->m_PackedData.GetType() == TYPE_PLACED);
  8811. D3D12MA_SWAP(m_Resource, allocation->m_Resource);
  8812. m_PackedData.SetWasZeroInitialized(allocation->m_PackedData.WasZeroInitialized());
  8813. m_Placed.block->m_pMetadata->SetAllocationPrivateData(m_Placed.allocHandle, allocation);
  8814. D3D12MA_SWAP(m_Placed, allocation->m_Placed);
  8815. m_Placed.block->m_pMetadata->SetAllocationPrivateData(m_Placed.allocHandle, this);
  8816. }
  8817. AllocHandle Allocation::GetAllocHandle() const
  8818. {
  8819. switch (m_PackedData.GetType())
  8820. {
  8821. case TYPE_COMMITTED:
  8822. case TYPE_HEAP:
  8823. return (AllocHandle)0;
  8824. case TYPE_PLACED:
  8825. return m_Placed.allocHandle;
  8826. default:
  8827. D3D12MA_ASSERT(0);
  8828. return (AllocHandle)0;
  8829. }
  8830. }
  8831. NormalBlock* Allocation::GetBlock()
  8832. {
  8833. switch (m_PackedData.GetType())
  8834. {
  8835. case TYPE_COMMITTED:
  8836. case TYPE_HEAP:
  8837. return NULL;
  8838. case TYPE_PLACED:
  8839. return m_Placed.block;
  8840. default:
  8841. D3D12MA_ASSERT(0);
  8842. return NULL;
  8843. }
  8844. }
  8845. template<typename D3D12_RESOURCE_DESC_T>
  8846. void Allocation::SetResourcePointer(ID3D12Resource* resource, const D3D12_RESOURCE_DESC_T* pResourceDesc)
  8847. {
  8848. D3D12MA_ASSERT(m_Resource == NULL && pResourceDesc);
  8849. m_Resource = resource;
  8850. m_PackedData.SetResourceDimension(pResourceDesc->Dimension);
  8851. m_PackedData.SetResourceFlags(pResourceDesc->Flags);
  8852. m_PackedData.SetTextureLayout(pResourceDesc->Layout);
  8853. }
  8854. void Allocation::FreeName()
  8855. {
  8856. if (m_Name)
  8857. {
  8858. const size_t nameCharCount = wcslen(m_Name) + 1;
  8859. D3D12MA_DELETE_ARRAY(m_Allocator->GetAllocs(), m_Name, nameCharCount);
  8860. m_Name = NULL;
  8861. }
  8862. }
  8863. #endif // _D3D12MA_ALLOCATION_FUNCTIONS
  8864. #ifndef _D3D12MA_DEFRAGMENTATION_CONTEXT_FUNCTIONS
  8865. HRESULT DefragmentationContext::BeginPass(DEFRAGMENTATION_PASS_MOVE_INFO* pPassInfo)
  8866. {
  8867. D3D12MA_ASSERT(pPassInfo);
  8868. return m_Pimpl->DefragmentPassBegin(*pPassInfo);
  8869. }
  8870. HRESULT DefragmentationContext::EndPass(DEFRAGMENTATION_PASS_MOVE_INFO* pPassInfo)
  8871. {
  8872. D3D12MA_ASSERT(pPassInfo);
  8873. return m_Pimpl->DefragmentPassEnd(*pPassInfo);
  8874. }
  8875. void DefragmentationContext::GetStats(DEFRAGMENTATION_STATS* pStats)
  8876. {
  8877. D3D12MA_ASSERT(pStats);
  8878. m_Pimpl->GetStats(*pStats);
  8879. }
  8880. void DefragmentationContext::ReleaseThis()
  8881. {
  8882. if (this == NULL)
  8883. {
  8884. return;
  8885. }
  8886. D3D12MA_DELETE(m_Pimpl->GetAllocs(), this);
  8887. }
  8888. DefragmentationContext::DefragmentationContext(AllocatorPimpl* allocator,
  8889. const DEFRAGMENTATION_DESC& desc,
  8890. BlockVector* poolVector)
  8891. : m_Pimpl(D3D12MA_NEW(allocator->GetAllocs(), DefragmentationContextPimpl)(allocator, desc, poolVector)) {}
  8892. DefragmentationContext::~DefragmentationContext()
  8893. {
  8894. D3D12MA_DELETE(m_Pimpl->GetAllocs(), m_Pimpl);
  8895. }
  8896. #endif // _D3D12MA_DEFRAGMENTATION_CONTEXT_FUNCTIONS
  8897. #ifndef _D3D12MA_POOL_FUNCTIONS
  8898. POOL_DESC Pool::GetDesc() const
  8899. {
  8900. return m_Pimpl->GetDesc();
  8901. }
  8902. void Pool::GetStatistics(Statistics* pStats)
  8903. {
  8904. D3D12MA_ASSERT(pStats);
  8905. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  8906. m_Pimpl->GetStatistics(*pStats);
  8907. }
  8908. void Pool::CalculateStatistics(DetailedStatistics* pStats)
  8909. {
  8910. D3D12MA_ASSERT(pStats);
  8911. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  8912. m_Pimpl->CalculateStatistics(*pStats);
  8913. }
  8914. void Pool::SetName(LPCWSTR Name)
  8915. {
  8916. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  8917. m_Pimpl->SetName(Name);
  8918. }
  8919. LPCWSTR Pool::GetName() const
  8920. {
  8921. return m_Pimpl->GetName();
  8922. }
  8923. HRESULT Pool::BeginDefragmentation(const DEFRAGMENTATION_DESC* pDesc, DefragmentationContext** ppContext)
  8924. {
  8925. D3D12MA_ASSERT(pDesc && ppContext);
  8926. // Check for support
  8927. if (m_Pimpl->GetBlockVector()->GetAlgorithm() & POOL_FLAG_ALGORITHM_LINEAR)
  8928. return E_NOINTERFACE;
  8929. AllocatorPimpl* allocator = m_Pimpl->GetAllocator();
  8930. *ppContext = D3D12MA_NEW(allocator->GetAllocs(), DefragmentationContext)(allocator, *pDesc, m_Pimpl->GetBlockVector());
  8931. return S_OK;
  8932. }
  8933. void Pool::ReleaseThis()
  8934. {
  8935. if (this == NULL)
  8936. {
  8937. return;
  8938. }
  8939. D3D12MA_DELETE(m_Pimpl->GetAllocator()->GetAllocs(), this);
  8940. }
  8941. Pool::Pool(Allocator* allocator, const POOL_DESC& desc)
  8942. : m_Pimpl(D3D12MA_NEW(allocator->m_Pimpl->GetAllocs(), PoolPimpl)(allocator->m_Pimpl, desc)) {}
  8943. Pool::~Pool()
  8944. {
  8945. m_Pimpl->GetAllocator()->UnregisterPool(this, m_Pimpl->GetDesc().HeapProperties.Type);
  8946. D3D12MA_DELETE(m_Pimpl->GetAllocator()->GetAllocs(), m_Pimpl);
  8947. }
  8948. #endif // _D3D12MA_POOL_FUNCTIONS
  8949. #ifndef _D3D12MA_ALLOCATOR_FUNCTIONS
  8950. const D3D12_FEATURE_DATA_D3D12_OPTIONS& Allocator::GetD3D12Options() const
  8951. {
  8952. return m_Pimpl->GetD3D12Options();
  8953. }
  8954. BOOL Allocator::IsUMA() const
  8955. {
  8956. return m_Pimpl->IsUMA();
  8957. }
  8958. BOOL Allocator::IsCacheCoherentUMA() const
  8959. {
  8960. return m_Pimpl->IsCacheCoherentUMA();
  8961. }
  8962. UINT64 Allocator::GetMemoryCapacity(UINT memorySegmentGroup) const
  8963. {
  8964. return m_Pimpl->GetMemoryCapacity(memorySegmentGroup);
  8965. }
  8966. HRESULT Allocator::CreateResource(
  8967. const ALLOCATION_DESC* pAllocDesc,
  8968. const D3D12_RESOURCE_DESC* pResourceDesc,
  8969. D3D12_RESOURCE_STATES InitialResourceState,
  8970. const D3D12_CLEAR_VALUE* pOptimizedClearValue,
  8971. Allocation** ppAllocation,
  8972. REFIID riidResource,
  8973. void** ppvResource)
  8974. {
  8975. if (!pAllocDesc || !pResourceDesc || !ppAllocation)
  8976. {
  8977. D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::CreateResource.");
  8978. return E_INVALIDARG;
  8979. }
  8980. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  8981. return m_Pimpl->CreateResource(
  8982. pAllocDesc,
  8983. CREATE_RESOURCE_PARAMS(pResourceDesc, InitialResourceState, pOptimizedClearValue),
  8984. ppAllocation,
  8985. riidResource,
  8986. ppvResource);
  8987. }
  8988. #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  8989. HRESULT Allocator::CreateResource2(
  8990. const ALLOCATION_DESC* pAllocDesc,
  8991. const D3D12_RESOURCE_DESC1* pResourceDesc,
  8992. D3D12_RESOURCE_STATES InitialResourceState,
  8993. const D3D12_CLEAR_VALUE* pOptimizedClearValue,
  8994. Allocation** ppAllocation,
  8995. REFIID riidResource,
  8996. void** ppvResource)
  8997. {
  8998. if (!pAllocDesc || !pResourceDesc || !ppAllocation)
  8999. {
  9000. D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::CreateResource2.");
  9001. return E_INVALIDARG;
  9002. }
  9003. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  9004. return m_Pimpl->CreateResource(
  9005. pAllocDesc,
  9006. CREATE_RESOURCE_PARAMS(pResourceDesc, InitialResourceState, pOptimizedClearValue),
  9007. ppAllocation,
  9008. riidResource,
  9009. ppvResource);
  9010. }
  9011. #endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  9012. #ifdef __ID3D12Device10_INTERFACE_DEFINED__
  9013. HRESULT Allocator::CreateResource3(
  9014. const ALLOCATION_DESC* pAllocDesc,
  9015. const D3D12_RESOURCE_DESC1* pResourceDesc,
  9016. D3D12_BARRIER_LAYOUT InitialLayout,
  9017. const D3D12_CLEAR_VALUE* pOptimizedClearValue,
  9018. UINT32 NumCastableFormats,
  9019. DXGI_FORMAT* pCastableFormats,
  9020. Allocation** ppAllocation,
  9021. REFIID riidResource,
  9022. void** ppvResource)
  9023. {
  9024. if (!pAllocDesc || !pResourceDesc || !ppAllocation)
  9025. {
  9026. D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::CreateResource3.");
  9027. return E_INVALIDARG;
  9028. }
  9029. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  9030. return m_Pimpl->CreateResource(
  9031. pAllocDesc,
  9032. CREATE_RESOURCE_PARAMS(pResourceDesc, InitialLayout, pOptimizedClearValue, NumCastableFormats, pCastableFormats),
  9033. ppAllocation,
  9034. riidResource,
  9035. ppvResource);
  9036. }
  9037. #endif // #ifdef __ID3D12Device10_INTERFACE_DEFINED__
  9038. HRESULT Allocator::AllocateMemory(
  9039. const ALLOCATION_DESC* pAllocDesc,
  9040. const D3D12_RESOURCE_ALLOCATION_INFO* pAllocInfo,
  9041. Allocation** ppAllocation)
  9042. {
  9043. if (!ValidateAllocateMemoryParameters(pAllocDesc, pAllocInfo, ppAllocation))
  9044. {
  9045. D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::AllocateMemory.");
  9046. return E_INVALIDARG;
  9047. }
  9048. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  9049. return m_Pimpl->AllocateMemory(pAllocDesc, pAllocInfo, ppAllocation);
  9050. }
  9051. HRESULT Allocator::CreateAliasingResource(
  9052. Allocation* pAllocation,
  9053. UINT64 AllocationLocalOffset,
  9054. const D3D12_RESOURCE_DESC* pResourceDesc,
  9055. D3D12_RESOURCE_STATES InitialResourceState,
  9056. const D3D12_CLEAR_VALUE* pOptimizedClearValue,
  9057. REFIID riidResource,
  9058. void** ppvResource)
  9059. {
  9060. if (!pAllocation || !pResourceDesc || !ppvResource)
  9061. {
  9062. D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::CreateAliasingResource.");
  9063. return E_INVALIDARG;
  9064. }
  9065. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  9066. return m_Pimpl->CreateAliasingResource(
  9067. pAllocation,
  9068. AllocationLocalOffset,
  9069. CREATE_RESOURCE_PARAMS(pResourceDesc, InitialResourceState, pOptimizedClearValue),
  9070. riidResource,
  9071. ppvResource);
  9072. }
  9073. #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  9074. HRESULT Allocator::CreateAliasingResource1(
  9075. Allocation* pAllocation,
  9076. UINT64 AllocationLocalOffset,
  9077. const D3D12_RESOURCE_DESC1* pResourceDesc,
  9078. D3D12_RESOURCE_STATES InitialResourceState,
  9079. const D3D12_CLEAR_VALUE* pOptimizedClearValue,
  9080. REFIID riidResource,
  9081. void** ppvResource)
  9082. {
  9083. if (!pAllocation || !pResourceDesc || !ppvResource)
  9084. {
  9085. D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::CreateAliasingResource.");
  9086. return E_INVALIDARG;
  9087. }
  9088. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  9089. return m_Pimpl->CreateAliasingResource(
  9090. pAllocation,
  9091. AllocationLocalOffset,
  9092. CREATE_RESOURCE_PARAMS(pResourceDesc, InitialResourceState, pOptimizedClearValue),
  9093. riidResource,
  9094. ppvResource);
  9095. }
  9096. #endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
  9097. #ifdef __ID3D12Device10_INTERFACE_DEFINED__
  9098. HRESULT Allocator::CreateAliasingResource2(
  9099. Allocation* pAllocation,
  9100. UINT64 AllocationLocalOffset,
  9101. const D3D12_RESOURCE_DESC1* pResourceDesc,
  9102. D3D12_BARRIER_LAYOUT InitialLayout,
  9103. const D3D12_CLEAR_VALUE* pOptimizedClearValue,
  9104. UINT32 NumCastableFormats,
  9105. DXGI_FORMAT* pCastableFormats,
  9106. REFIID riidResource,
  9107. void** ppvResource)
  9108. {
  9109. if (!pAllocation || !pResourceDesc || !ppvResource)
  9110. {
  9111. D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::CreateAliasingResource.");
  9112. return E_INVALIDARG;
  9113. }
  9114. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  9115. return m_Pimpl->CreateAliasingResource(
  9116. pAllocation,
  9117. AllocationLocalOffset,
  9118. CREATE_RESOURCE_PARAMS(pResourceDesc, InitialLayout, pOptimizedClearValue, NumCastableFormats, pCastableFormats),
  9119. riidResource,
  9120. ppvResource);
  9121. }
  9122. #endif // #ifdef __ID3D12Device10_INTERFACE_DEFINED__
  9123. HRESULT Allocator::CreatePool(
  9124. const POOL_DESC* pPoolDesc,
  9125. Pool** ppPool)
  9126. {
  9127. if (!pPoolDesc || !ppPool ||
  9128. (pPoolDesc->MaxBlockCount > 0 && pPoolDesc->MaxBlockCount < pPoolDesc->MinBlockCount) ||
  9129. (pPoolDesc->MinAllocationAlignment > 0 && !IsPow2(pPoolDesc->MinAllocationAlignment)))
  9130. {
  9131. D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::CreatePool.");
  9132. return E_INVALIDARG;
  9133. }
  9134. if (!m_Pimpl->HeapFlagsFulfillResourceHeapTier(pPoolDesc->HeapFlags))
  9135. {
  9136. D3D12MA_ASSERT(0 && "Invalid pPoolDesc->HeapFlags passed to Allocator::CreatePool. Did you forget to handle ResourceHeapTier=1?");
  9137. return E_INVALIDARG;
  9138. }
  9139. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  9140. * ppPool = D3D12MA_NEW(m_Pimpl->GetAllocs(), Pool)(this, *pPoolDesc);
  9141. HRESULT hr = (*ppPool)->m_Pimpl->Init();
  9142. if (SUCCEEDED(hr))
  9143. {
  9144. m_Pimpl->RegisterPool(*ppPool, pPoolDesc->HeapProperties.Type);
  9145. }
  9146. else
  9147. {
  9148. D3D12MA_DELETE(m_Pimpl->GetAllocs(), *ppPool);
  9149. *ppPool = NULL;
  9150. }
  9151. return hr;
  9152. }
  9153. void Allocator::SetCurrentFrameIndex(UINT frameIndex)
  9154. {
  9155. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  9156. m_Pimpl->SetCurrentFrameIndex(frameIndex);
  9157. }
  9158. void Allocator::GetBudget(Budget* pLocalBudget, Budget* pNonLocalBudget)
  9159. {
  9160. if (pLocalBudget == NULL && pNonLocalBudget == NULL)
  9161. {
  9162. return;
  9163. }
  9164. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  9165. m_Pimpl->GetBudget(pLocalBudget, pNonLocalBudget);
  9166. }
  9167. void Allocator::CalculateStatistics(TotalStatistics* pStats)
  9168. {
  9169. D3D12MA_ASSERT(pStats);
  9170. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  9171. m_Pimpl->CalculateStatistics(*pStats);
  9172. }
  9173. void Allocator::BuildStatsString(WCHAR** ppStatsString, BOOL DetailedMap) const
  9174. {
  9175. D3D12MA_ASSERT(ppStatsString);
  9176. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  9177. m_Pimpl->BuildStatsString(ppStatsString, DetailedMap);
  9178. }
  9179. void Allocator::FreeStatsString(WCHAR* pStatsString) const
  9180. {
  9181. if (pStatsString != NULL)
  9182. {
  9183. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  9184. m_Pimpl->FreeStatsString(pStatsString);
  9185. }
  9186. }
  9187. void Allocator::BeginDefragmentation(const DEFRAGMENTATION_DESC* pDesc, DefragmentationContext** ppContext)
  9188. {
  9189. D3D12MA_ASSERT(pDesc && ppContext);
  9190. *ppContext = D3D12MA_NEW(m_Pimpl->GetAllocs(), DefragmentationContext)(m_Pimpl, *pDesc, NULL);
  9191. }
  9192. void Allocator::ReleaseThis()
  9193. {
  9194. // Copy is needed because otherwise we would call destructor and invalidate the structure with callbacks before using it to free memory.
  9195. const ALLOCATION_CALLBACKS allocationCallbacksCopy = m_Pimpl->GetAllocs();
  9196. D3D12MA_DELETE(allocationCallbacksCopy, this);
  9197. }
  9198. Allocator::Allocator(const ALLOCATION_CALLBACKS& allocationCallbacks, const ALLOCATOR_DESC& desc)
  9199. : m_Pimpl(D3D12MA_NEW(allocationCallbacks, AllocatorPimpl)(allocationCallbacks, desc)) {}
  9200. Allocator::~Allocator()
  9201. {
  9202. D3D12MA_DELETE(m_Pimpl->GetAllocs(), m_Pimpl);
  9203. }
  9204. #endif // _D3D12MA_ALLOCATOR_FUNCTIONS
  9205. #ifndef _D3D12MA_VIRTUAL_BLOCK_FUNCTIONS
  9206. BOOL VirtualBlock::IsEmpty() const
  9207. {
  9208. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  9209. return m_Pimpl->m_Metadata->IsEmpty() ? TRUE : FALSE;
  9210. }
  9211. void VirtualBlock::GetAllocationInfo(VirtualAllocation allocation, VIRTUAL_ALLOCATION_INFO* pInfo) const
  9212. {
  9213. D3D12MA_ASSERT(allocation.AllocHandle != (AllocHandle)0 && pInfo);
  9214. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  9215. m_Pimpl->m_Metadata->GetAllocationInfo(allocation.AllocHandle, *pInfo);
  9216. }
  9217. HRESULT VirtualBlock::Allocate(const VIRTUAL_ALLOCATION_DESC* pDesc, VirtualAllocation* pAllocation, UINT64* pOffset)
  9218. {
  9219. if (!pDesc || !pAllocation || pDesc->Size == 0 || !IsPow2(pDesc->Alignment))
  9220. {
  9221. D3D12MA_ASSERT(0 && "Invalid arguments passed to VirtualBlock::Allocate.");
  9222. return E_INVALIDARG;
  9223. }
  9224. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  9225. const UINT64 alignment = pDesc->Alignment != 0 ? pDesc->Alignment : 1;
  9226. AllocationRequest allocRequest = {};
  9227. if (m_Pimpl->m_Metadata->CreateAllocationRequest(
  9228. pDesc->Size,
  9229. alignment,
  9230. pDesc->Flags & VIRTUAL_ALLOCATION_FLAG_UPPER_ADDRESS,
  9231. pDesc->Flags & VIRTUAL_ALLOCATION_FLAG_STRATEGY_MASK,
  9232. &allocRequest))
  9233. {
  9234. m_Pimpl->m_Metadata->Alloc(allocRequest, pDesc->Size, pDesc->pPrivateData);
  9235. D3D12MA_HEAVY_ASSERT(m_Pimpl->m_Metadata->Validate());
  9236. pAllocation->AllocHandle = allocRequest.allocHandle;
  9237. if (pOffset)
  9238. *pOffset = m_Pimpl->m_Metadata->GetAllocationOffset(allocRequest.allocHandle);
  9239. return S_OK;
  9240. }
  9241. pAllocation->AllocHandle = (AllocHandle)0;
  9242. if (pOffset)
  9243. *pOffset = UINT64_MAX;
  9244. return E_OUTOFMEMORY;
  9245. }
  9246. void VirtualBlock::FreeAllocation(VirtualAllocation allocation)
  9247. {
  9248. if (allocation.AllocHandle == (AllocHandle)0)
  9249. return;
  9250. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  9251. m_Pimpl->m_Metadata->Free(allocation.AllocHandle);
  9252. D3D12MA_HEAVY_ASSERT(m_Pimpl->m_Metadata->Validate());
  9253. }
  9254. void VirtualBlock::Clear()
  9255. {
  9256. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  9257. m_Pimpl->m_Metadata->Clear();
  9258. D3D12MA_HEAVY_ASSERT(m_Pimpl->m_Metadata->Validate());
  9259. }
  9260. void VirtualBlock::SetAllocationPrivateData(VirtualAllocation allocation, void* pPrivateData)
  9261. {
  9262. D3D12MA_ASSERT(allocation.AllocHandle != (AllocHandle)0);
  9263. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  9264. m_Pimpl->m_Metadata->SetAllocationPrivateData(allocation.AllocHandle, pPrivateData);
  9265. }
  9266. void VirtualBlock::GetStatistics(Statistics* pStats) const
  9267. {
  9268. D3D12MA_ASSERT(pStats);
  9269. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  9270. D3D12MA_HEAVY_ASSERT(m_Pimpl->m_Metadata->Validate());
  9271. ClearStatistics(*pStats);
  9272. m_Pimpl->m_Metadata->AddStatistics(*pStats);
  9273. }
  9274. void VirtualBlock::CalculateStatistics(DetailedStatistics* pStats) const
  9275. {
  9276. D3D12MA_ASSERT(pStats);
  9277. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  9278. D3D12MA_HEAVY_ASSERT(m_Pimpl->m_Metadata->Validate());
  9279. ClearDetailedStatistics(*pStats);
  9280. m_Pimpl->m_Metadata->AddDetailedStatistics(*pStats);
  9281. }
  9282. void VirtualBlock::BuildStatsString(WCHAR** ppStatsString) const
  9283. {
  9284. D3D12MA_ASSERT(ppStatsString);
  9285. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  9286. StringBuilder sb(m_Pimpl->m_AllocationCallbacks);
  9287. {
  9288. JsonWriter json(m_Pimpl->m_AllocationCallbacks, sb);
  9289. D3D12MA_HEAVY_ASSERT(m_Pimpl->m_Metadata->Validate());
  9290. json.BeginObject();
  9291. m_Pimpl->m_Metadata->WriteAllocationInfoToJson(json);
  9292. json.EndObject();
  9293. } // Scope for JsonWriter
  9294. const size_t length = sb.GetLength();
  9295. WCHAR* result = AllocateArray<WCHAR>(m_Pimpl->m_AllocationCallbacks, length + 1);
  9296. memcpy(result, sb.GetData(), length * sizeof(WCHAR));
  9297. result[length] = L'\0';
  9298. *ppStatsString = result;
  9299. }
  9300. void VirtualBlock::FreeStatsString(WCHAR* pStatsString) const
  9301. {
  9302. if (pStatsString != NULL)
  9303. {
  9304. D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
  9305. D3D12MA::Free(m_Pimpl->m_AllocationCallbacks, pStatsString);
  9306. }
  9307. }
  9308. void VirtualBlock::ReleaseThis()
  9309. {
  9310. // Copy is needed because otherwise we would call destructor and invalidate the structure with callbacks before using it to free memory.
  9311. const ALLOCATION_CALLBACKS allocationCallbacksCopy = m_Pimpl->m_AllocationCallbacks;
  9312. D3D12MA_DELETE(allocationCallbacksCopy, this);
  9313. }
  9314. VirtualBlock::VirtualBlock(const ALLOCATION_CALLBACKS& allocationCallbacks, const VIRTUAL_BLOCK_DESC& desc)
  9315. : m_Pimpl(D3D12MA_NEW(allocationCallbacks, VirtualBlockPimpl)(allocationCallbacks, desc)) {}
  9316. VirtualBlock::~VirtualBlock()
  9317. {
  9318. // THIS IS AN IMPORTANT ASSERT!
  9319. // Hitting it means you have some memory leak - unreleased allocations in this virtual block.
  9320. D3D12MA_ASSERT(m_Pimpl->m_Metadata->IsEmpty() && "Some allocations were not freed before destruction of this virtual block!");
  9321. D3D12MA_DELETE(m_Pimpl->m_AllocationCallbacks, m_Pimpl);
  9322. }
  9323. #endif // _D3D12MA_VIRTUAL_BLOCK_FUNCTIONS
  9324. #endif // _D3D12MA_PUBLIC_INTERFACE
  9325. } // namespace D3D12MA