1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562 |
- //
- // Copyright (c) 2019-2022 Advanced Micro Devices, Inc. All rights reserved.
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- //
- #include "D3D12MemAlloc.h"
- #include <combaseapi.h>
- #include <mutex>
- #include <algorithm>
- #include <utility>
- #include <cstdlib>
- #include <cstdint>
- #include <malloc.h> // for _aligned_malloc, _aligned_free
- #ifndef _WIN32
- #include <shared_mutex>
- #endif
- #if !defined(_MSC_VER)
- #include <guiddef.h>
- #include <dxguids.h>
- #endif
- ////////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Configuration Begin
- //
- ////////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////
- #ifndef _D3D12MA_CONFIGURATION
- #ifdef _WIN32
- #if !defined(WINVER) || WINVER < 0x0600
- #error Required at least WinAPI version supporting: client = Windows Vista, server = Windows Server 2008.
- #endif
- #endif
- #ifndef D3D12MA_SORT
- #define D3D12MA_SORT(beg, end, cmp) std::sort(beg, end, cmp)
- #endif
- #ifndef D3D12MA_D3D12_HEADERS_ALREADY_INCLUDED
- #include <dxgi.h>
- #if D3D12MA_DXGI_1_4
- #include <dxgi1_4.h>
- #endif
- #endif
- #ifndef D3D12MA_ASSERT
- #include <cassert>
- #define D3D12MA_ASSERT(cond) assert(cond)
- #endif
- // Assert that will be called very often, like inside data structures e.g. operator[].
- // Making it non-empty can make program slow.
- #ifndef D3D12MA_HEAVY_ASSERT
- #ifdef _DEBUG
- #define D3D12MA_HEAVY_ASSERT(expr) //D3D12MA_ASSERT(expr)
- #else
- #define D3D12MA_HEAVY_ASSERT(expr)
- #endif
- #endif
- #ifndef D3D12MA_DEBUG_ALIGNMENT
- /*
- Minimum alignment of all allocations, in bytes.
- Set to more than 1 for debugging purposes only. Must be power of two.
- */
- #define D3D12MA_DEBUG_ALIGNMENT (1)
- #endif
- #ifndef D3D12MA_DEBUG_MARGIN
- // Minimum margin before and after every allocation, in bytes.
- // Set nonzero for debugging purposes only.
- #define D3D12MA_DEBUG_MARGIN (0)
- #endif
- #ifndef D3D12MA_DEBUG_GLOBAL_MUTEX
- /*
- Set this to 1 for debugging purposes only, to enable single mutex protecting all
- entry calls to the library. Can be useful for debugging multithreading issues.
- */
- #define D3D12MA_DEBUG_GLOBAL_MUTEX (0)
- #endif
- /*
- Define this macro for debugging purposes only to force specific D3D12_RESOURCE_HEAP_TIER,
- especially to test compatibility with D3D12_RESOURCE_HEAP_TIER_1 on modern GPUs.
- */
- //#define D3D12MA_FORCE_RESOURCE_HEAP_TIER D3D12_RESOURCE_HEAP_TIER_1
- #ifndef D3D12MA_DEFAULT_BLOCK_SIZE
- /// Default size of a block allocated as single ID3D12Heap.
- #define D3D12MA_DEFAULT_BLOCK_SIZE (64ull * 1024 * 1024)
- #endif
- #ifndef D3D12MA_DEBUG_LOG
- #define D3D12MA_DEBUG_LOG(format, ...)
- /*
- #define D3D12MA_DEBUG_LOG(format, ...) do { \
- wprintf(format, __VA_ARGS__); \
- wprintf(L"\n"); \
- } while(false)
- */
- #endif
- #endif // _D3D12MA_CONFIGURATION
- ////////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Configuration End
- //
- ////////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////
- #define D3D12MA_IID_PPV_ARGS(ppType) __uuidof(**(ppType)), reinterpret_cast<void**>(ppType)
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- #define D3D12MA_CREATE_NOT_ZEROED_AVAILABLE 1
- #endif
- namespace D3D12MA
- {
- static constexpr UINT HEAP_TYPE_COUNT = 4;
- static constexpr UINT STANDARD_HEAP_TYPE_COUNT = 3; // Only DEFAULT, UPLOAD, READBACK.
- static constexpr UINT DEFAULT_POOL_MAX_COUNT = 9;
- static const UINT NEW_BLOCK_SIZE_SHIFT_MAX = 3;
- // Minimum size of a free suballocation to register it in the free suballocation collection.
- static const UINT64 MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER = 16;
- static const WCHAR* const HeapTypeNames[] =
- {
- L"DEFAULT",
- L"UPLOAD",
- L"READBACK",
- L"CUSTOM",
- };
- static const D3D12_HEAP_FLAGS RESOURCE_CLASS_HEAP_FLAGS =
- D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES | D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
- static const D3D12_RESIDENCY_PRIORITY D3D12_RESIDENCY_PRIORITY_NONE = D3D12_RESIDENCY_PRIORITY(0);
- #ifndef _D3D12MA_ENUM_DECLARATIONS
- // Local copy of this enum, as it is provided only by <dxgi1_4.h>, so it may not be available.
- enum DXGI_MEMORY_SEGMENT_GROUP_COPY
- {
- DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY = 0,
- DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY = 1,
- DXGI_MEMORY_SEGMENT_GROUP_COUNT
- };
- enum class ResourceClass
- {
- Unknown, Buffer, Non_RT_DS_Texture, RT_DS_Texture
- };
- enum SuballocationType
- {
- SUBALLOCATION_TYPE_FREE = 0,
- SUBALLOCATION_TYPE_ALLOCATION = 1,
- };
- #endif // _D3D12MA_ENUM_DECLARATIONS
- #ifndef _D3D12MA_FUNCTIONS
- static void* DefaultAllocate(size_t Size, size_t Alignment, void* /*pPrivateData*/)
- {
- #ifdef _WIN32
- return _aligned_malloc(Size, Alignment);
- #else
- return aligned_alloc(Alignment, Size);
- #endif
- }
- static void DefaultFree(void* pMemory, void* /*pPrivateData*/)
- {
- #ifdef _WIN32
- return _aligned_free(pMemory);
- #else
- return free(pMemory);
- #endif
- }
- static void* Malloc(const ALLOCATION_CALLBACKS& allocs, size_t size, size_t alignment)
- {
- void* const result = (*allocs.pAllocate)(size, alignment, allocs.pPrivateData);
- D3D12MA_ASSERT(result);
- return result;
- }
- static void Free(const ALLOCATION_CALLBACKS& allocs, void* memory)
- {
- (*allocs.pFree)(memory, allocs.pPrivateData);
- }
- template<typename T>
- static T* Allocate(const ALLOCATION_CALLBACKS& allocs)
- {
- return (T*)Malloc(allocs, sizeof(T), __alignof(T));
- }
- template<typename T>
- static T* AllocateArray(const ALLOCATION_CALLBACKS& allocs, size_t count)
- {
- return (T*)Malloc(allocs, sizeof(T) * count, __alignof(T));
- }
- #define D3D12MA_NEW(allocs, type) new(D3D12MA::Allocate<type>(allocs))(type)
- #define D3D12MA_NEW_ARRAY(allocs, type, count) new(D3D12MA::AllocateArray<type>((allocs), (count)))(type)
- template<typename T>
- void D3D12MA_DELETE(const ALLOCATION_CALLBACKS& allocs, T* memory)
- {
- if (memory)
- {
- memory->~T();
- Free(allocs, memory);
- }
- }
- template<typename T>
- void D3D12MA_DELETE_ARRAY(const ALLOCATION_CALLBACKS& allocs, T* memory, size_t count)
- {
- if (memory)
- {
- for (size_t i = count; i--; )
- {
- memory[i].~T();
- }
- Free(allocs, memory);
- }
- }
- static void SetupAllocationCallbacks(ALLOCATION_CALLBACKS& outAllocs, const ALLOCATION_CALLBACKS* allocationCallbacks)
- {
- if (allocationCallbacks)
- {
- outAllocs = *allocationCallbacks;
- D3D12MA_ASSERT(outAllocs.pAllocate != NULL && outAllocs.pFree != NULL);
- }
- else
- {
- outAllocs.pAllocate = &DefaultAllocate;
- outAllocs.pFree = &DefaultFree;
- outAllocs.pPrivateData = NULL;
- }
- }
- #define SAFE_RELEASE(ptr) do { if(ptr) { (ptr)->Release(); (ptr) = NULL; } } while(false)
- #define D3D12MA_VALIDATE(cond) do { if(!(cond)) { \
- D3D12MA_ASSERT(0 && "Validation failed: " #cond); \
- return false; \
- } } while(false)
- template<typename T>
- static T D3D12MA_MIN(const T& a, const T& b) { return a <= b ? a : b; }
- template<typename T>
- static T D3D12MA_MAX(const T& a, const T& b) { return a <= b ? b : a; }
- template<typename T>
- static void D3D12MA_SWAP(T& a, T& b) { T tmp = a; a = b; b = tmp; }
- // Scans integer for index of first nonzero bit from the Least Significant Bit (LSB). If mask is 0 then returns UINT8_MAX
- static UINT8 BitScanLSB(UINT64 mask)
- {
- #if defined(_MSC_VER) && defined(_WIN64)
- unsigned long pos;
- if (_BitScanForward64(&pos, mask))
- return static_cast<UINT8>(pos);
- return UINT8_MAX;
- #elif defined __GNUC__ || defined __clang__
- return static_cast<UINT8>(__builtin_ffsll(mask)) - 1U;
- #else
- UINT8 pos = 0;
- UINT64 bit = 1;
- do
- {
- if (mask & bit)
- return pos;
- bit <<= 1;
- } while (pos++ < 63);
- return UINT8_MAX;
- #endif
- }
- // Scans integer for index of first nonzero bit from the Least Significant Bit (LSB). If mask is 0 then returns UINT8_MAX
- static UINT8 BitScanLSB(UINT32 mask)
- {
- #ifdef _MSC_VER
- unsigned long pos;
- if (_BitScanForward(&pos, mask))
- return static_cast<UINT8>(pos);
- return UINT8_MAX;
- #elif defined __GNUC__ || defined __clang__
- return static_cast<UINT8>(__builtin_ffs(mask)) - 1U;
- #else
- UINT8 pos = 0;
- UINT32 bit = 1;
- do
- {
- if (mask & bit)
- return pos;
- bit <<= 1;
- } while (pos++ < 31);
- return UINT8_MAX;
- #endif
- }
- // Scans integer for index of first nonzero bit from the Most Significant Bit (MSB). If mask is 0 then returns UINT8_MAX
- static UINT8 BitScanMSB(UINT64 mask)
- {
- #if defined(_MSC_VER) && defined(_WIN64)
- unsigned long pos;
- if (_BitScanReverse64(&pos, mask))
- return static_cast<UINT8>(pos);
- #elif defined __GNUC__ || defined __clang__
- if (mask)
- return 63 - static_cast<UINT8>(__builtin_clzll(mask));
- #else
- UINT8 pos = 63;
- UINT64 bit = 1ULL << 63;
- do
- {
- if (mask & bit)
- return pos;
- bit >>= 1;
- } while (pos-- > 0);
- #endif
- return UINT8_MAX;
- }
- // Scans integer for index of first nonzero bit from the Most Significant Bit (MSB). If mask is 0 then returns UINT8_MAX
- static UINT8 BitScanMSB(UINT32 mask)
- {
- #ifdef _MSC_VER
- unsigned long pos;
- if (_BitScanReverse(&pos, mask))
- return static_cast<UINT8>(pos);
- #elif defined __GNUC__ || defined __clang__
- if (mask)
- return 31 - static_cast<UINT8>(__builtin_clz(mask));
- #else
- UINT8 pos = 31;
- UINT32 bit = 1UL << 31;
- do
- {
- if (mask & bit)
- return pos;
- bit >>= 1;
- } while (pos-- > 0);
- #endif
- return UINT8_MAX;
- }
- /*
- Returns true if given number is a power of two.
- T must be unsigned integer number or signed integer but always nonnegative.
- For 0 returns true.
- */
- template <typename T>
- static bool IsPow2(T x) { return (x & (x - 1)) == 0; }
- // Aligns given value up to nearest multiply of align value. For example: AlignUp(11, 8) = 16.
- // Use types like UINT, uint64_t as T.
- template <typename T>
- static T AlignUp(T val, T alignment)
- {
- D3D12MA_HEAVY_ASSERT(IsPow2(alignment));
- return (val + alignment - 1) & ~(alignment - 1);
- }
- // Aligns given value down to nearest multiply of align value. For example: AlignUp(11, 8) = 8.
- // Use types like UINT, uint64_t as T.
- template <typename T>
- static T AlignDown(T val, T alignment)
- {
- D3D12MA_HEAVY_ASSERT(IsPow2(alignment));
- return val & ~(alignment - 1);
- }
- // Division with mathematical rounding to nearest number.
- template <typename T>
- static T RoundDiv(T x, T y) { return (x + (y / (T)2)) / y; }
- template <typename T>
- static T DivideRoundingUp(T x, T y) { return (x + y - 1) / y; }
- static WCHAR HexDigitToChar(UINT8 digit)
- {
- if(digit < 10)
- return L'0' + digit;
- else
- return L'A' + (digit - 10);
- }
- /*
- Performs binary search and returns iterator to first element that is greater or
- equal to `key`, according to comparison `cmp`.
- Cmp should return true if first argument is less than second argument.
- Returned value is the found element, if present in the collection or place where
- new element with value (key) should be inserted.
- */
- template <typename CmpLess, typename IterT, typename KeyT>
- static IterT BinaryFindFirstNotLess(IterT beg, IterT end, const KeyT& key, const CmpLess& cmp)
- {
- size_t down = 0, up = (end - beg);
- while (down < up)
- {
- const size_t mid = (down + up) / 2;
- if (cmp(*(beg + mid), key))
- {
- down = mid + 1;
- }
- else
- {
- up = mid;
- }
- }
- return beg + down;
- }
- /*
- Performs binary search and returns iterator to an element that is equal to `key`,
- according to comparison `cmp`.
- Cmp should return true if first argument is less than second argument.
- Returned value is the found element, if present in the collection or end if not
- found.
- */
- template<typename CmpLess, typename IterT, typename KeyT>
- static IterT BinaryFindSorted(const IterT& beg, const IterT& end, const KeyT& value, const CmpLess& cmp)
- {
- IterT it = BinaryFindFirstNotLess<CmpLess, IterT, KeyT>(beg, end, value, cmp);
- if (it == end ||
- (!cmp(*it, value) && !cmp(value, *it)))
- {
- return it;
- }
- return end;
- }
- static UINT HeapTypeToIndex(D3D12_HEAP_TYPE type)
- {
- switch (type)
- {
- case D3D12_HEAP_TYPE_DEFAULT: return 0;
- case D3D12_HEAP_TYPE_UPLOAD: return 1;
- case D3D12_HEAP_TYPE_READBACK: return 2;
- case D3D12_HEAP_TYPE_CUSTOM: return 3;
- default: D3D12MA_ASSERT(0); return UINT_MAX;
- }
- }
- static D3D12_HEAP_TYPE IndexToHeapType(UINT heapTypeIndex)
- {
- D3D12MA_ASSERT(heapTypeIndex < 4);
- // D3D12_HEAP_TYPE_DEFAULT starts at 1.
- return (D3D12_HEAP_TYPE)(heapTypeIndex + 1);
- }
- static UINT64 HeapFlagsToAlignment(D3D12_HEAP_FLAGS flags, bool denyMsaaTextures)
- {
- /*
- Documentation of D3D12_HEAP_DESC structure says:
- - D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT defined as 64KB.
- - D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT defined as 4MB. An
- application must decide whether the heap will contain multi-sample
- anti-aliasing (MSAA), in which case, the application must choose [this flag].
- https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ns-d3d12-d3d12_heap_desc
- */
- if (denyMsaaTextures)
- return D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
- const D3D12_HEAP_FLAGS denyAllTexturesFlags =
- D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES | D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES;
- const bool canContainAnyTextures =
- (flags & denyAllTexturesFlags) != denyAllTexturesFlags;
- return canContainAnyTextures ?
- D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT : D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
- }
- static ResourceClass HeapFlagsToResourceClass(D3D12_HEAP_FLAGS heapFlags)
- {
- const bool allowBuffers = (heapFlags & D3D12_HEAP_FLAG_DENY_BUFFERS) == 0;
- const bool allowRtDsTextures = (heapFlags & D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES) == 0;
- const bool allowNonRtDsTextures = (heapFlags & D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES) == 0;
- const uint8_t allowedGroupCount = (allowBuffers ? 1 : 0) + (allowRtDsTextures ? 1 : 0) + (allowNonRtDsTextures ? 1 : 0);
- if (allowedGroupCount != 1)
- return ResourceClass::Unknown;
- if (allowRtDsTextures)
- return ResourceClass::RT_DS_Texture;
- if (allowNonRtDsTextures)
- return ResourceClass::Non_RT_DS_Texture;
- return ResourceClass::Buffer;
- }
- static bool IsHeapTypeStandard(D3D12_HEAP_TYPE type)
- {
- return type == D3D12_HEAP_TYPE_DEFAULT ||
- type == D3D12_HEAP_TYPE_UPLOAD ||
- type == D3D12_HEAP_TYPE_READBACK;
- }
- static D3D12_HEAP_PROPERTIES StandardHeapTypeToHeapProperties(D3D12_HEAP_TYPE type)
- {
- D3D12MA_ASSERT(IsHeapTypeStandard(type));
- D3D12_HEAP_PROPERTIES result = {};
- result.Type = type;
- return result;
- }
- static bool IsFormatCompressed(DXGI_FORMAT format)
- {
- switch (format)
- {
- case DXGI_FORMAT_BC1_TYPELESS:
- case DXGI_FORMAT_BC1_UNORM:
- case DXGI_FORMAT_BC1_UNORM_SRGB:
- case DXGI_FORMAT_BC2_TYPELESS:
- case DXGI_FORMAT_BC2_UNORM:
- case DXGI_FORMAT_BC2_UNORM_SRGB:
- case DXGI_FORMAT_BC3_TYPELESS:
- case DXGI_FORMAT_BC3_UNORM:
- case DXGI_FORMAT_BC3_UNORM_SRGB:
- case DXGI_FORMAT_BC4_TYPELESS:
- case DXGI_FORMAT_BC4_UNORM:
- case DXGI_FORMAT_BC4_SNORM:
- case DXGI_FORMAT_BC5_TYPELESS:
- case DXGI_FORMAT_BC5_UNORM:
- case DXGI_FORMAT_BC5_SNORM:
- case DXGI_FORMAT_BC6H_TYPELESS:
- case DXGI_FORMAT_BC6H_UF16:
- case DXGI_FORMAT_BC6H_SF16:
- case DXGI_FORMAT_BC7_TYPELESS:
- case DXGI_FORMAT_BC7_UNORM:
- case DXGI_FORMAT_BC7_UNORM_SRGB:
- return true;
- default:
- return false;
- }
- }
- // Only some formats are supported. For others it returns 0.
- static UINT GetBitsPerPixel(DXGI_FORMAT format)
- {
- switch (format)
- {
- case DXGI_FORMAT_R32G32B32A32_TYPELESS:
- case DXGI_FORMAT_R32G32B32A32_FLOAT:
- case DXGI_FORMAT_R32G32B32A32_UINT:
- case DXGI_FORMAT_R32G32B32A32_SINT:
- return 128;
- case DXGI_FORMAT_R32G32B32_TYPELESS:
- case DXGI_FORMAT_R32G32B32_FLOAT:
- case DXGI_FORMAT_R32G32B32_UINT:
- case DXGI_FORMAT_R32G32B32_SINT:
- return 96;
- case DXGI_FORMAT_R16G16B16A16_TYPELESS:
- case DXGI_FORMAT_R16G16B16A16_FLOAT:
- case DXGI_FORMAT_R16G16B16A16_UNORM:
- case DXGI_FORMAT_R16G16B16A16_UINT:
- case DXGI_FORMAT_R16G16B16A16_SNORM:
- case DXGI_FORMAT_R16G16B16A16_SINT:
- return 64;
- case DXGI_FORMAT_R32G32_TYPELESS:
- case DXGI_FORMAT_R32G32_FLOAT:
- case DXGI_FORMAT_R32G32_UINT:
- case DXGI_FORMAT_R32G32_SINT:
- return 64;
- case DXGI_FORMAT_R32G8X24_TYPELESS:
- case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
- case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
- case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
- return 64;
- case DXGI_FORMAT_R10G10B10A2_TYPELESS:
- case DXGI_FORMAT_R10G10B10A2_UNORM:
- case DXGI_FORMAT_R10G10B10A2_UINT:
- case DXGI_FORMAT_R11G11B10_FLOAT:
- return 32;
- case DXGI_FORMAT_R8G8B8A8_TYPELESS:
- case DXGI_FORMAT_R8G8B8A8_UNORM:
- case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
- case DXGI_FORMAT_R8G8B8A8_UINT:
- case DXGI_FORMAT_R8G8B8A8_SNORM:
- case DXGI_FORMAT_R8G8B8A8_SINT:
- return 32;
- case DXGI_FORMAT_R16G16_TYPELESS:
- case DXGI_FORMAT_R16G16_FLOAT:
- case DXGI_FORMAT_R16G16_UNORM:
- case DXGI_FORMAT_R16G16_UINT:
- case DXGI_FORMAT_R16G16_SNORM:
- case DXGI_FORMAT_R16G16_SINT:
- return 32;
- case DXGI_FORMAT_R32_TYPELESS:
- case DXGI_FORMAT_D32_FLOAT:
- case DXGI_FORMAT_R32_FLOAT:
- case DXGI_FORMAT_R32_UINT:
- case DXGI_FORMAT_R32_SINT:
- return 32;
- case DXGI_FORMAT_R24G8_TYPELESS:
- case DXGI_FORMAT_D24_UNORM_S8_UINT:
- case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
- case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
- return 32;
- case DXGI_FORMAT_R8G8_TYPELESS:
- case DXGI_FORMAT_R8G8_UNORM:
- case DXGI_FORMAT_R8G8_UINT:
- case DXGI_FORMAT_R8G8_SNORM:
- case DXGI_FORMAT_R8G8_SINT:
- return 16;
- case DXGI_FORMAT_R16_TYPELESS:
- case DXGI_FORMAT_R16_FLOAT:
- case DXGI_FORMAT_D16_UNORM:
- case DXGI_FORMAT_R16_UNORM:
- case DXGI_FORMAT_R16_UINT:
- case DXGI_FORMAT_R16_SNORM:
- case DXGI_FORMAT_R16_SINT:
- return 16;
- case DXGI_FORMAT_R8_TYPELESS:
- case DXGI_FORMAT_R8_UNORM:
- case DXGI_FORMAT_R8_UINT:
- case DXGI_FORMAT_R8_SNORM:
- case DXGI_FORMAT_R8_SINT:
- case DXGI_FORMAT_A8_UNORM:
- return 8;
- case DXGI_FORMAT_BC1_TYPELESS:
- case DXGI_FORMAT_BC1_UNORM:
- case DXGI_FORMAT_BC1_UNORM_SRGB:
- return 4;
- case DXGI_FORMAT_BC2_TYPELESS:
- case DXGI_FORMAT_BC2_UNORM:
- case DXGI_FORMAT_BC2_UNORM_SRGB:
- return 8;
- case DXGI_FORMAT_BC3_TYPELESS:
- case DXGI_FORMAT_BC3_UNORM:
- case DXGI_FORMAT_BC3_UNORM_SRGB:
- return 8;
- case DXGI_FORMAT_BC4_TYPELESS:
- case DXGI_FORMAT_BC4_UNORM:
- case DXGI_FORMAT_BC4_SNORM:
- return 4;
- case DXGI_FORMAT_BC5_TYPELESS:
- case DXGI_FORMAT_BC5_UNORM:
- case DXGI_FORMAT_BC5_SNORM:
- return 8;
- case DXGI_FORMAT_BC6H_TYPELESS:
- case DXGI_FORMAT_BC6H_UF16:
- case DXGI_FORMAT_BC6H_SF16:
- return 8;
- case DXGI_FORMAT_BC7_TYPELESS:
- case DXGI_FORMAT_BC7_UNORM:
- case DXGI_FORMAT_BC7_UNORM_SRGB:
- return 8;
- default:
- return 0;
- }
- }
-
- template<typename D3D12_RESOURCE_DESC_T>
- static ResourceClass ResourceDescToResourceClass(const D3D12_RESOURCE_DESC_T& resDesc)
- {
- if (resDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
- return ResourceClass::Buffer;
- // Else: it's surely a texture.
- const bool isRenderTargetOrDepthStencil =
- (resDesc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) != 0;
- return isRenderTargetOrDepthStencil ? ResourceClass::RT_DS_Texture : ResourceClass::Non_RT_DS_Texture;
- }
-
- // This algorithm is overly conservative.
- template<typename D3D12_RESOURCE_DESC_T>
- static bool CanUseSmallAlignment(const D3D12_RESOURCE_DESC_T& resourceDesc)
- {
- if (resourceDesc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D)
- return false;
- if ((resourceDesc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) != 0)
- return false;
- if (resourceDesc.SampleDesc.Count > 1)
- return false;
- if (resourceDesc.DepthOrArraySize != 1)
- return false;
- UINT sizeX = (UINT)resourceDesc.Width;
- UINT sizeY = resourceDesc.Height;
- UINT bitsPerPixel = GetBitsPerPixel(resourceDesc.Format);
- if (bitsPerPixel == 0)
- return false;
- if (IsFormatCompressed(resourceDesc.Format))
- {
- sizeX = DivideRoundingUp(sizeX, 4u);
- sizeY = DivideRoundingUp(sizeY, 4u);
- bitsPerPixel *= 16;
- }
- UINT tileSizeX = 0, tileSizeY = 0;
- switch (bitsPerPixel)
- {
- case 8: tileSizeX = 64; tileSizeY = 64; break;
- case 16: tileSizeX = 64; tileSizeY = 32; break;
- case 32: tileSizeX = 32; tileSizeY = 32; break;
- case 64: tileSizeX = 32; tileSizeY = 16; break;
- case 128: tileSizeX = 16; tileSizeY = 16; break;
- default: return false;
- }
- const UINT tileCount = DivideRoundingUp(sizeX, tileSizeX) * DivideRoundingUp(sizeY, tileSizeY);
- return tileCount <= 16;
- }
-
- static bool ValidateAllocateMemoryParameters(
- const ALLOCATION_DESC* pAllocDesc,
- const D3D12_RESOURCE_ALLOCATION_INFO* pAllocInfo,
- Allocation** ppAllocation)
- {
- return pAllocDesc &&
- pAllocInfo &&
- ppAllocation &&
- (pAllocInfo->Alignment == 0 ||
- pAllocInfo->Alignment == D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT ||
- pAllocInfo->Alignment == D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT) &&
- pAllocInfo->SizeInBytes != 0 &&
- pAllocInfo->SizeInBytes % (64ull * 1024) == 0;
- }
- #endif // _D3D12MA_FUNCTIONS
-
- #ifndef _D3D12MA_STATISTICS_FUNCTIONS
- static void ClearStatistics(Statistics& outStats)
- {
- outStats.BlockCount = 0;
- outStats.AllocationCount = 0;
- outStats.BlockBytes = 0;
- outStats.AllocationBytes = 0;
- }
- static void ClearDetailedStatistics(DetailedStatistics& outStats)
- {
- ClearStatistics(outStats.Stats);
- outStats.UnusedRangeCount = 0;
- outStats.AllocationSizeMin = UINT64_MAX;
- outStats.AllocationSizeMax = 0;
- outStats.UnusedRangeSizeMin = UINT64_MAX;
- outStats.UnusedRangeSizeMax = 0;
- }
- static void AddStatistics(Statistics& inoutStats, const Statistics& src)
- {
- inoutStats.BlockCount += src.BlockCount;
- inoutStats.AllocationCount += src.AllocationCount;
- inoutStats.BlockBytes += src.BlockBytes;
- inoutStats.AllocationBytes += src.AllocationBytes;
- }
- static void AddDetailedStatistics(DetailedStatistics& inoutStats, const DetailedStatistics& src)
- {
- AddStatistics(inoutStats.Stats, src.Stats);
- inoutStats.UnusedRangeCount += src.UnusedRangeCount;
- inoutStats.AllocationSizeMin = D3D12MA_MIN(inoutStats.AllocationSizeMin, src.AllocationSizeMin);
- inoutStats.AllocationSizeMax = D3D12MA_MAX(inoutStats.AllocationSizeMax, src.AllocationSizeMax);
- inoutStats.UnusedRangeSizeMin = D3D12MA_MIN(inoutStats.UnusedRangeSizeMin, src.UnusedRangeSizeMin);
- inoutStats.UnusedRangeSizeMax = D3D12MA_MAX(inoutStats.UnusedRangeSizeMax, src.UnusedRangeSizeMax);
- }
- static void AddDetailedStatisticsAllocation(DetailedStatistics& inoutStats, UINT64 size)
- {
- inoutStats.Stats.AllocationCount++;
- inoutStats.Stats.AllocationBytes += size;
- inoutStats.AllocationSizeMin = D3D12MA_MIN(inoutStats.AllocationSizeMin, size);
- inoutStats.AllocationSizeMax = D3D12MA_MAX(inoutStats.AllocationSizeMax, size);
- }
- static void AddDetailedStatisticsUnusedRange(DetailedStatistics& inoutStats, UINT64 size)
- {
- inoutStats.UnusedRangeCount++;
- inoutStats.UnusedRangeSizeMin = D3D12MA_MIN(inoutStats.UnusedRangeSizeMin, size);
- inoutStats.UnusedRangeSizeMax = D3D12MA_MAX(inoutStats.UnusedRangeSizeMax, size);
- }
-
- #endif // _D3D12MA_STATISTICS_FUNCTIONS
- #ifndef _D3D12MA_MUTEX
- #ifndef D3D12MA_MUTEX
- class Mutex
- {
- public:
- void Lock() { m_Mutex.lock(); }
- void Unlock() { m_Mutex.unlock(); }
-
- private:
- std::mutex m_Mutex;
- };
- #define D3D12MA_MUTEX Mutex
- #endif
- #ifndef D3D12MA_RW_MUTEX
- #ifdef _WIN32
- class RWMutex
- {
- public:
- RWMutex() { InitializeSRWLock(&m_Lock); }
- void LockRead() { AcquireSRWLockShared(&m_Lock); }
- void UnlockRead() { ReleaseSRWLockShared(&m_Lock); }
- void LockWrite() { AcquireSRWLockExclusive(&m_Lock); }
- void UnlockWrite() { ReleaseSRWLockExclusive(&m_Lock); }
-
- private:
- SRWLOCK m_Lock;
- };
- #else // #ifdef _WIN32
- class RWMutex
- {
- public:
- RWMutex() {}
- void LockRead() { m_Mutex.lock_shared(); }
- void UnlockRead() { m_Mutex.unlock_shared(); }
- void LockWrite() { m_Mutex.lock(); }
- void UnlockWrite() { m_Mutex.unlock(); }
-
- private:
- std::shared_timed_mutex m_Mutex;
- };
- #endif // #ifdef _WIN32
- #define D3D12MA_RW_MUTEX RWMutex
- #endif // #ifndef D3D12MA_RW_MUTEX
- // Helper RAII class to lock a mutex in constructor and unlock it in destructor (at the end of scope).
- struct MutexLock
- {
- D3D12MA_CLASS_NO_COPY(MutexLock);
- public:
- MutexLock(D3D12MA_MUTEX& mutex, bool useMutex = true) :
- m_pMutex(useMutex ? &mutex : NULL)
- {
- if (m_pMutex) m_pMutex->Lock();
- }
- ~MutexLock() { if (m_pMutex) m_pMutex->Unlock(); }
- private:
- D3D12MA_MUTEX* m_pMutex;
- };
- // Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for reading.
- struct MutexLockRead
- {
- D3D12MA_CLASS_NO_COPY(MutexLockRead);
- public:
- MutexLockRead(D3D12MA_RW_MUTEX& mutex, bool useMutex)
- : m_pMutex(useMutex ? &mutex : NULL)
- {
- if(m_pMutex)
- {
- m_pMutex->LockRead();
- }
- }
- ~MutexLockRead() { if (m_pMutex) m_pMutex->UnlockRead(); }
- private:
- D3D12MA_RW_MUTEX* m_pMutex;
- };
- // Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for writing.
- struct MutexLockWrite
- {
- D3D12MA_CLASS_NO_COPY(MutexLockWrite);
- public:
- MutexLockWrite(D3D12MA_RW_MUTEX& mutex, bool useMutex)
- : m_pMutex(useMutex ? &mutex : NULL)
- {
- if (m_pMutex) m_pMutex->LockWrite();
- }
- ~MutexLockWrite() { if (m_pMutex) m_pMutex->UnlockWrite(); }
- private:
- D3D12MA_RW_MUTEX* m_pMutex;
- };
- #if D3D12MA_DEBUG_GLOBAL_MUTEX
- static D3D12MA_MUTEX g_DebugGlobalMutex;
- #define D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK MutexLock debugGlobalMutexLock(g_DebugGlobalMutex, true);
- #else
- #define D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- #endif
- #endif // _D3D12MA_MUTEX
- #ifndef _D3D12MA_VECTOR
- /*
- Dynamically resizing continuous array. Class with interface similar to std::vector.
- T must be POD because constructors and destructors are not called and memcpy is
- used for these objects.
- */
- template<typename T>
- class Vector
- {
- public:
- using value_type = T;
- using iterator = T*;
- using const_iterator = const T*;
- // allocationCallbacks externally owned, must outlive this object.
- Vector(const ALLOCATION_CALLBACKS& allocationCallbacks);
- Vector(size_t count, const ALLOCATION_CALLBACKS& allocationCallbacks);
- Vector(const Vector<T>& src);
- ~Vector();
- const ALLOCATION_CALLBACKS& GetAllocs() const { return m_AllocationCallbacks; }
- bool empty() const { return m_Count == 0; }
- size_t size() const { return m_Count; }
- T* data() { return m_pArray; }
- const T* data() const { return m_pArray; }
- void clear(bool freeMemory = false) { resize(0, freeMemory); }
- iterator begin() { return m_pArray; }
- iterator end() { return m_pArray + m_Count; }
- const_iterator cbegin() const { return m_pArray; }
- const_iterator cend() const { return m_pArray + m_Count; }
- const_iterator begin() const { return cbegin(); }
- const_iterator end() const { return cend(); }
- void push_front(const T& src) { insert(0, src); }
- void push_back(const T& src);
- void pop_front();
- void pop_back();
- T& front();
- T& back();
- const T& front() const;
- const T& back() const;
- void reserve(size_t newCapacity, bool freeMemory = false);
- void resize(size_t newCount, bool freeMemory = false);
- void insert(size_t index, const T& src);
- void remove(size_t index);
- template<typename CmpLess>
- size_t InsertSorted(const T& value, const CmpLess& cmp);
- template<typename CmpLess>
- bool RemoveSorted(const T& value, const CmpLess& cmp);
- Vector& operator=(const Vector<T>& rhs);
- T& operator[](size_t index);
- const T& operator[](size_t index) const;
- private:
- const ALLOCATION_CALLBACKS& m_AllocationCallbacks;
- T* m_pArray;
- size_t m_Count;
- size_t m_Capacity;
- };
- #ifndef _D3D12MA_VECTOR_FUNCTIONS
- template<typename T>
- Vector<T>::Vector(const ALLOCATION_CALLBACKS& allocationCallbacks)
- : m_AllocationCallbacks(allocationCallbacks),
- m_pArray(NULL),
- m_Count(0),
- m_Capacity(0) {}
- template<typename T>
- Vector<T>::Vector(size_t count, const ALLOCATION_CALLBACKS& allocationCallbacks)
- : m_AllocationCallbacks(allocationCallbacks),
- m_pArray(count ? AllocateArray<T>(allocationCallbacks, count) : NULL),
- m_Count(count),
- m_Capacity(count) {}
- template<typename T>
- Vector<T>::Vector(const Vector<T>& src)
- : m_AllocationCallbacks(src.m_AllocationCallbacks),
- m_pArray(src.m_Count ? AllocateArray<T>(src.m_AllocationCallbacks, src.m_Count) : NULL),
- m_Count(src.m_Count),
- m_Capacity(src.m_Count)
- {
- if (m_Count > 0)
- {
- memcpy(m_pArray, src.m_pArray, m_Count * sizeof(T));
- }
- }
- template<typename T>
- Vector<T>::~Vector()
- {
- Free(m_AllocationCallbacks, m_pArray);
- }
- template<typename T>
- void Vector<T>::push_back(const T& src)
- {
- const size_t newIndex = size();
- resize(newIndex + 1);
- m_pArray[newIndex] = src;
- }
- template<typename T>
- void Vector<T>::pop_front()
- {
- D3D12MA_HEAVY_ASSERT(m_Count > 0);
- remove(0);
- }
- template<typename T>
- void Vector<T>::pop_back()
- {
- D3D12MA_HEAVY_ASSERT(m_Count > 0);
- resize(size() - 1);
- }
- template<typename T>
- T& Vector<T>::front()
- {
- D3D12MA_HEAVY_ASSERT(m_Count > 0);
- return m_pArray[0];
- }
- template<typename T>
- T& Vector<T>::back()
- {
- D3D12MA_HEAVY_ASSERT(m_Count > 0);
- return m_pArray[m_Count - 1];
- }
- template<typename T>
- const T& Vector<T>::front() const
- {
- D3D12MA_HEAVY_ASSERT(m_Count > 0);
- return m_pArray[0];
- }
- template<typename T>
- const T& Vector<T>::back() const
- {
- D3D12MA_HEAVY_ASSERT(m_Count > 0);
- return m_pArray[m_Count - 1];
- }
- template<typename T>
- void Vector<T>::reserve(size_t newCapacity, bool freeMemory)
- {
- newCapacity = D3D12MA_MAX(newCapacity, m_Count);
- if ((newCapacity < m_Capacity) && !freeMemory)
- {
- newCapacity = m_Capacity;
- }
- if (newCapacity != m_Capacity)
- {
- T* const newArray = newCapacity ? AllocateArray<T>(m_AllocationCallbacks, newCapacity) : NULL;
- if (m_Count != 0)
- {
- memcpy(newArray, m_pArray, m_Count * sizeof(T));
- }
- Free(m_AllocationCallbacks, m_pArray);
- m_Capacity = newCapacity;
- m_pArray = newArray;
- }
- }
- template<typename T>
- void Vector<T>::resize(size_t newCount, bool freeMemory)
- {
- size_t newCapacity = m_Capacity;
- if (newCount > m_Capacity)
- {
- newCapacity = D3D12MA_MAX(newCount, D3D12MA_MAX(m_Capacity * 3 / 2, (size_t)8));
- }
- else if (freeMemory)
- {
- newCapacity = newCount;
- }
- if (newCapacity != m_Capacity)
- {
- T* const newArray = newCapacity ? AllocateArray<T>(m_AllocationCallbacks, newCapacity) : NULL;
- const size_t elementsToCopy = D3D12MA_MIN(m_Count, newCount);
- if (elementsToCopy != 0)
- {
- memcpy(newArray, m_pArray, elementsToCopy * sizeof(T));
- }
- Free(m_AllocationCallbacks, m_pArray);
- m_Capacity = newCapacity;
- m_pArray = newArray;
- }
- m_Count = newCount;
- }
- template<typename T>
- void Vector<T>::insert(size_t index, const T& src)
- {
- D3D12MA_HEAVY_ASSERT(index <= m_Count);
- const size_t oldCount = size();
- resize(oldCount + 1);
- if (index < oldCount)
- {
- memmove(m_pArray + (index + 1), m_pArray + index, (oldCount - index) * sizeof(T));
- }
- m_pArray[index] = src;
- }
- template<typename T>
- void Vector<T>::remove(size_t index)
- {
- D3D12MA_HEAVY_ASSERT(index < m_Count);
- const size_t oldCount = size();
- if (index < oldCount - 1)
- {
- memmove(m_pArray + index, m_pArray + (index + 1), (oldCount - index - 1) * sizeof(T));
- }
- resize(oldCount - 1);
- }
- template<typename T> template<typename CmpLess>
- size_t Vector<T>::InsertSorted(const T& value, const CmpLess& cmp)
- {
- const size_t indexToInsert = BinaryFindFirstNotLess<CmpLess, iterator, T>(
- m_pArray,
- m_pArray + m_Count,
- value,
- cmp) - m_pArray;
- insert(indexToInsert, value);
- return indexToInsert;
- }
- template<typename T> template<typename CmpLess>
- bool Vector<T>::RemoveSorted(const T& value, const CmpLess& cmp)
- {
- const iterator it = BinaryFindFirstNotLess(
- m_pArray,
- m_pArray + m_Count,
- value,
- cmp);
- if ((it != end()) && !cmp(*it, value) && !cmp(value, *it))
- {
- size_t indexToRemove = it - begin();
- remove(indexToRemove);
- return true;
- }
- return false;
- }
- template<typename T>
- Vector<T>& Vector<T>::operator=(const Vector<T>& rhs)
- {
- if (&rhs != this)
- {
- resize(rhs.m_Count);
- if (m_Count != 0)
- {
- memcpy(m_pArray, rhs.m_pArray, m_Count * sizeof(T));
- }
- }
- return *this;
- }
- template<typename T>
- T& Vector<T>::operator[](size_t index)
- {
- D3D12MA_HEAVY_ASSERT(index < m_Count);
- return m_pArray[index];
- }
- template<typename T>
- const T& Vector<T>::operator[](size_t index) const
- {
- D3D12MA_HEAVY_ASSERT(index < m_Count);
- return m_pArray[index];
- }
- #endif // _D3D12MA_VECTOR_FUNCTIONS
- #endif // _D3D12MA_VECTOR
- #ifndef _D3D12MA_STRING_BUILDER
- class StringBuilder
- {
- public:
- StringBuilder(const ALLOCATION_CALLBACKS& allocationCallbacks) : m_Data(allocationCallbacks) {}
- size_t GetLength() const { return m_Data.size(); }
- LPCWSTR GetData() const { return m_Data.data(); }
- void Add(WCHAR ch) { m_Data.push_back(ch); }
- void Add(LPCWSTR str);
- void AddNewLine() { Add(L'\n'); }
- void AddNumber(UINT num);
- void AddNumber(UINT64 num);
- void AddPointer(const void* ptr);
- private:
- Vector<WCHAR> m_Data;
- };
- #ifndef _D3D12MA_STRING_BUILDER_FUNCTIONS
- void StringBuilder::Add(LPCWSTR str)
- {
- const size_t len = wcslen(str);
- if (len > 0)
- {
- const size_t oldCount = m_Data.size();
- m_Data.resize(oldCount + len);
- memcpy(m_Data.data() + oldCount, str, len * sizeof(WCHAR));
- }
- }
- void StringBuilder::AddNumber(UINT num)
- {
- WCHAR buf[11];
- buf[10] = L'\0';
- WCHAR *p = &buf[10];
- do
- {
- *--p = L'0' + (num % 10);
- num /= 10;
- }
- while (num);
- Add(p);
- }
- void StringBuilder::AddNumber(UINT64 num)
- {
- WCHAR buf[21];
- buf[20] = L'\0';
- WCHAR *p = &buf[20];
- do
- {
- *--p = L'0' + (num % 10);
- num /= 10;
- }
- while (num);
- Add(p);
- }
- void StringBuilder::AddPointer(const void* ptr)
- {
- WCHAR buf[21];
- uintptr_t num = (uintptr_t)ptr;
- buf[20] = L'\0';
- WCHAR *p = &buf[20];
- do
- {
- *--p = HexDigitToChar((UINT8)(num & 0xF));
- num >>= 4;
- }
- while (num);
- Add(p);
- }
- #endif // _D3D12MA_STRING_BUILDER_FUNCTIONS
- #endif // _D3D12MA_STRING_BUILDER
- #ifndef _D3D12MA_JSON_WRITER
- /*
- Allows to conveniently build a correct JSON document to be written to the
- StringBuilder passed to the constructor.
- */
- class JsonWriter
- {
- public:
- // stringBuilder - string builder to write the document to. Must remain alive for the whole lifetime of this object.
- JsonWriter(const ALLOCATION_CALLBACKS& allocationCallbacks, StringBuilder& stringBuilder);
- ~JsonWriter();
- // Begins object by writing "{".
- // Inside an object, you must call pairs of WriteString and a value, e.g.:
- // j.BeginObject(true); j.WriteString("A"); j.WriteNumber(1); j.WriteString("B"); j.WriteNumber(2); j.EndObject();
- // Will write: { "A": 1, "B": 2 }
- void BeginObject(bool singleLine = false);
- // Ends object by writing "}".
- void EndObject();
- // Begins array by writing "[".
- // Inside an array, you can write a sequence of any values.
- void BeginArray(bool singleLine = false);
- // Ends array by writing "[".
- void EndArray();
- // Writes a string value inside "".
- // pStr can contain any UTF-16 characters, including '"', new line etc. - they will be properly escaped.
- void WriteString(LPCWSTR pStr);
- // Begins writing a string value.
- // Call BeginString, ContinueString, ContinueString, ..., EndString instead of
- // WriteString to conveniently build the string content incrementally, made of
- // parts including numbers.
- void BeginString(LPCWSTR pStr = NULL);
- // Posts next part of an open string.
- void ContinueString(LPCWSTR pStr);
- // Posts next part of an open string. The number is converted to decimal characters.
- void ContinueString(UINT num);
- void ContinueString(UINT64 num);
- void ContinueString_Pointer(const void* ptr);
- // Posts next part of an open string. Pointer value is converted to characters
- // using "%p" formatting - shown as hexadecimal number, e.g.: 000000081276Ad00
- // void ContinueString_Pointer(const void* ptr);
- // Ends writing a string value by writing '"'.
- void EndString(LPCWSTR pStr = NULL);
- // Writes a number value.
- void WriteNumber(UINT num);
- void WriteNumber(UINT64 num);
- // Writes a boolean value - false or true.
- void WriteBool(bool b);
- // Writes a null value.
- void WriteNull();
- void AddAllocationToObject(const Allocation& alloc);
- void AddDetailedStatisticsInfoObject(const DetailedStatistics& stats);
- private:
- static const WCHAR* const INDENT;
- enum CollectionType
- {
- COLLECTION_TYPE_OBJECT,
- COLLECTION_TYPE_ARRAY,
- };
- struct StackItem
- {
- CollectionType type;
- UINT valueCount;
- bool singleLineMode;
- };
- StringBuilder& m_SB;
- Vector<StackItem> m_Stack;
- bool m_InsideString;
- void BeginValue(bool isString);
- void WriteIndent(bool oneLess = false);
- };
- #ifndef _D3D12MA_JSON_WRITER_FUNCTIONS
- const WCHAR* const JsonWriter::INDENT = L" ";
- JsonWriter::JsonWriter(const ALLOCATION_CALLBACKS& allocationCallbacks, StringBuilder& stringBuilder)
- : m_SB(stringBuilder),
- m_Stack(allocationCallbacks),
- m_InsideString(false) {}
- JsonWriter::~JsonWriter()
- {
- D3D12MA_ASSERT(!m_InsideString);
- D3D12MA_ASSERT(m_Stack.empty());
- }
- void JsonWriter::BeginObject(bool singleLine)
- {
- D3D12MA_ASSERT(!m_InsideString);
- BeginValue(false);
- m_SB.Add(L'{');
- StackItem stackItem;
- stackItem.type = COLLECTION_TYPE_OBJECT;
- stackItem.valueCount = 0;
- stackItem.singleLineMode = singleLine;
- m_Stack.push_back(stackItem);
- }
- void JsonWriter::EndObject()
- {
- D3D12MA_ASSERT(!m_InsideString);
- D3D12MA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_OBJECT);
- D3D12MA_ASSERT(m_Stack.back().valueCount % 2 == 0);
- WriteIndent(true);
- m_SB.Add(L'}');
- m_Stack.pop_back();
- }
- void JsonWriter::BeginArray(bool singleLine)
- {
- D3D12MA_ASSERT(!m_InsideString);
- BeginValue(false);
- m_SB.Add(L'[');
- StackItem stackItem;
- stackItem.type = COLLECTION_TYPE_ARRAY;
- stackItem.valueCount = 0;
- stackItem.singleLineMode = singleLine;
- m_Stack.push_back(stackItem);
- }
- void JsonWriter::EndArray()
- {
- D3D12MA_ASSERT(!m_InsideString);
- D3D12MA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_ARRAY);
- WriteIndent(true);
- m_SB.Add(L']');
- m_Stack.pop_back();
- }
- void JsonWriter::WriteString(LPCWSTR pStr)
- {
- BeginString(pStr);
- EndString();
- }
- void JsonWriter::BeginString(LPCWSTR pStr)
- {
- D3D12MA_ASSERT(!m_InsideString);
- BeginValue(true);
- m_InsideString = true;
- m_SB.Add(L'"');
- if (pStr != NULL)
- {
- ContinueString(pStr);
- }
- }
- void JsonWriter::ContinueString(LPCWSTR pStr)
- {
- D3D12MA_ASSERT(m_InsideString);
- D3D12MA_ASSERT(pStr);
- for (const WCHAR *p = pStr; *p; ++p)
- {
- // the strings we encode are assumed to be in UTF-16LE format, the native
- // windows wide character Unicode format. In this encoding Unicode code
- // points U+0000 to U+D7FF and U+E000 to U+FFFF are encoded in two bytes,
- // and everything else takes more than two bytes. We will reject any
- // multi wchar character encodings for simplicity.
- UINT val = (UINT)*p;
- D3D12MA_ASSERT(((val <= 0xD7FF) || (0xE000 <= val && val <= 0xFFFF)) &&
- "Character not currently supported.");
- switch (*p)
- {
- case L'"': m_SB.Add(L'\\'); m_SB.Add(L'"'); break;
- case L'\\': m_SB.Add(L'\\'); m_SB.Add(L'\\'); break;
- case L'/': m_SB.Add(L'\\'); m_SB.Add(L'/'); break;
- case L'\b': m_SB.Add(L'\\'); m_SB.Add(L'b'); break;
- case L'\f': m_SB.Add(L'\\'); m_SB.Add(L'f'); break;
- case L'\n': m_SB.Add(L'\\'); m_SB.Add(L'n'); break;
- case L'\r': m_SB.Add(L'\\'); m_SB.Add(L'r'); break;
- case L'\t': m_SB.Add(L'\\'); m_SB.Add(L't'); break;
- default:
- // conservatively use encoding \uXXXX for any Unicode character
- // requiring more than one byte.
- if (32 <= val && val < 256)
- m_SB.Add(*p);
- else
- {
- m_SB.Add(L'\\');
- m_SB.Add(L'u');
- for (UINT i = 0; i < 4; ++i)
- {
- UINT hexDigit = (val & 0xF000) >> 12;
- val <<= 4;
- if (hexDigit < 10)
- m_SB.Add(L'0' + (WCHAR)hexDigit);
- else
- m_SB.Add(L'A' + (WCHAR)hexDigit);
- }
- }
- break;
- }
- }
- }
- void JsonWriter::ContinueString(UINT num)
- {
- D3D12MA_ASSERT(m_InsideString);
- m_SB.AddNumber(num);
- }
- void JsonWriter::ContinueString(UINT64 num)
- {
- D3D12MA_ASSERT(m_InsideString);
- m_SB.AddNumber(num);
- }
- void JsonWriter::ContinueString_Pointer(const void* ptr)
- {
- D3D12MA_ASSERT(m_InsideString);
- m_SB.AddPointer(ptr);
- }
- void JsonWriter::EndString(LPCWSTR pStr)
- {
- D3D12MA_ASSERT(m_InsideString);
- if (pStr)
- ContinueString(pStr);
- m_SB.Add(L'"');
- m_InsideString = false;
- }
- void JsonWriter::WriteNumber(UINT num)
- {
- D3D12MA_ASSERT(!m_InsideString);
- BeginValue(false);
- m_SB.AddNumber(num);
- }
- void JsonWriter::WriteNumber(UINT64 num)
- {
- D3D12MA_ASSERT(!m_InsideString);
- BeginValue(false);
- m_SB.AddNumber(num);
- }
- void JsonWriter::WriteBool(bool b)
- {
- D3D12MA_ASSERT(!m_InsideString);
- BeginValue(false);
- if (b)
- m_SB.Add(L"true");
- else
- m_SB.Add(L"false");
- }
- void JsonWriter::WriteNull()
- {
- D3D12MA_ASSERT(!m_InsideString);
- BeginValue(false);
- m_SB.Add(L"null");
- }
- void JsonWriter::AddAllocationToObject(const Allocation& alloc)
- {
- WriteString(L"Type");
- switch (alloc.m_PackedData.GetResourceDimension()) {
- case D3D12_RESOURCE_DIMENSION_UNKNOWN:
- WriteString(L"UNKNOWN");
- break;
- case D3D12_RESOURCE_DIMENSION_BUFFER:
- WriteString(L"BUFFER");
- break;
- case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
- WriteString(L"TEXTURE1D");
- break;
- case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
- WriteString(L"TEXTURE2D");
- break;
- case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
- WriteString(L"TEXTURE3D");
- break;
- default: D3D12MA_ASSERT(0); break;
- }
- WriteString(L"Size");
- WriteNumber(alloc.GetSize());
- WriteString(L"Usage");
- WriteNumber((UINT)alloc.m_PackedData.GetResourceFlags());
- void* privateData = alloc.GetPrivateData();
- if (privateData)
- {
- WriteString(L"CustomData");
- BeginString();
- ContinueString_Pointer(privateData);
- EndString();
- }
- LPCWSTR name = alloc.GetName();
- if (name != NULL)
- {
- WriteString(L"Name");
- WriteString(name);
- }
- if (alloc.m_PackedData.GetTextureLayout())
- {
- WriteString(L"Layout");
- WriteNumber((UINT)alloc.m_PackedData.GetTextureLayout());
- }
- }
- void JsonWriter::AddDetailedStatisticsInfoObject(const DetailedStatistics& stats)
- {
- BeginObject();
- WriteString(L"BlockCount");
- WriteNumber(stats.Stats.BlockCount);
- WriteString(L"BlockBytes");
- WriteNumber(stats.Stats.BlockBytes);
- WriteString(L"AllocationCount");
- WriteNumber(stats.Stats.AllocationCount);
- WriteString(L"AllocationBytes");
- WriteNumber(stats.Stats.AllocationBytes);
- WriteString(L"UnusedRangeCount");
- WriteNumber(stats.UnusedRangeCount);
- if (stats.Stats.AllocationCount > 1)
- {
- WriteString(L"AllocationSizeMin");
- WriteNumber(stats.AllocationSizeMin);
- WriteString(L"AllocationSizeMax");
- WriteNumber(stats.AllocationSizeMax);
- }
- if (stats.UnusedRangeCount > 1)
- {
- WriteString(L"UnusedRangeSizeMin");
- WriteNumber(stats.UnusedRangeSizeMin);
- WriteString(L"UnusedRangeSizeMax");
- WriteNumber(stats.UnusedRangeSizeMax);
- }
- EndObject();
- }
- void JsonWriter::BeginValue(bool isString)
- {
- if (!m_Stack.empty())
- {
- StackItem& currItem = m_Stack.back();
- if (currItem.type == COLLECTION_TYPE_OBJECT && currItem.valueCount % 2 == 0)
- {
- D3D12MA_ASSERT(isString);
- }
- if (currItem.type == COLLECTION_TYPE_OBJECT && currItem.valueCount % 2 == 1)
- {
- m_SB.Add(L':'); m_SB.Add(L' ');
- }
- else if (currItem.valueCount > 0)
- {
- m_SB.Add(L','); m_SB.Add(L' ');
- WriteIndent();
- }
- else
- {
- WriteIndent();
- }
- ++currItem.valueCount;
- }
- }
- void JsonWriter::WriteIndent(bool oneLess)
- {
- if (!m_Stack.empty() && !m_Stack.back().singleLineMode)
- {
- m_SB.AddNewLine();
- size_t count = m_Stack.size();
- if (count > 0 && oneLess)
- {
- --count;
- }
- for (size_t i = 0; i < count; ++i)
- {
- m_SB.Add(INDENT);
- }
- }
- }
- #endif // _D3D12MA_JSON_WRITER_FUNCTIONS
- #endif // _D3D12MA_JSON_WRITER
- #ifndef _D3D12MA_POOL_ALLOCATOR
- /*
- Allocator for objects of type T using a list of arrays (pools) to speed up
- allocation. Number of elements that can be allocated is not bounded because
- allocator can create multiple blocks.
- T should be POD because constructor and destructor is not called in Alloc or
- Free.
- */
- template<typename T>
- class PoolAllocator
- {
- D3D12MA_CLASS_NO_COPY(PoolAllocator)
- public:
- // allocationCallbacks externally owned, must outlive this object.
- PoolAllocator(const ALLOCATION_CALLBACKS& allocationCallbacks, UINT firstBlockCapacity);
- ~PoolAllocator() { Clear(); }
- void Clear();
- template<typename... Types>
- T* Alloc(Types... args);
- void Free(T* ptr);
- private:
- union Item
- {
- UINT NextFreeIndex; // UINT32_MAX means end of list.
- alignas(T) char Value[sizeof(T)];
- };
- struct ItemBlock
- {
- Item* pItems;
- UINT Capacity;
- UINT FirstFreeIndex;
- };
- const ALLOCATION_CALLBACKS& m_AllocationCallbacks;
- const UINT m_FirstBlockCapacity;
- Vector<ItemBlock> m_ItemBlocks;
- ItemBlock& CreateNewBlock();
- };
- #ifndef _D3D12MA_POOL_ALLOCATOR_FUNCTIONS
- template<typename T>
- PoolAllocator<T>::PoolAllocator(const ALLOCATION_CALLBACKS& allocationCallbacks, UINT firstBlockCapacity)
- : m_AllocationCallbacks(allocationCallbacks),
- m_FirstBlockCapacity(firstBlockCapacity),
- m_ItemBlocks(allocationCallbacks)
- {
- D3D12MA_ASSERT(m_FirstBlockCapacity > 1);
- }
- template<typename T>
- void PoolAllocator<T>::Clear()
- {
- for(size_t i = m_ItemBlocks.size(); i--; )
- {
- D3D12MA_DELETE_ARRAY(m_AllocationCallbacks, m_ItemBlocks[i].pItems, m_ItemBlocks[i].Capacity);
- }
- m_ItemBlocks.clear(true);
- }
- template<typename T> template<typename... Types>
- T* PoolAllocator<T>::Alloc(Types... args)
- {
- for(size_t i = m_ItemBlocks.size(); i--; )
- {
- ItemBlock& block = m_ItemBlocks[i];
- // This block has some free items: Use first one.
- if(block.FirstFreeIndex != UINT32_MAX)
- {
- Item* const pItem = &block.pItems[block.FirstFreeIndex];
- block.FirstFreeIndex = pItem->NextFreeIndex;
- T* result = (T*)&pItem->Value;
- new(result)T(std::forward<Types>(args)...); // Explicit constructor call.
- return result;
- }
- }
- // No block has free item: Create new one and use it.
- ItemBlock& newBlock = CreateNewBlock();
- Item* const pItem = &newBlock.pItems[0];
- newBlock.FirstFreeIndex = pItem->NextFreeIndex;
- T* result = (T*)pItem->Value;
- new(result)T(std::forward<Types>(args)...); // Explicit constructor call.
- return result;
- }
- template<typename T>
- void PoolAllocator<T>::Free(T* ptr)
- {
- // Search all memory blocks to find ptr.
- for(size_t i = m_ItemBlocks.size(); i--; )
- {
- ItemBlock& block = m_ItemBlocks[i];
- Item* pItemPtr;
- memcpy(&pItemPtr, &ptr, sizeof(pItemPtr));
- // Check if pItemPtr is in address range of this block.
- if((pItemPtr >= block.pItems) && (pItemPtr < block.pItems + block.Capacity))
- {
- ptr->~T(); // Explicit destructor call.
- const UINT index = static_cast<UINT>(pItemPtr - block.pItems);
- pItemPtr->NextFreeIndex = block.FirstFreeIndex;
- block.FirstFreeIndex = index;
- return;
- }
- }
- D3D12MA_ASSERT(0 && "Pointer doesn't belong to this memory pool.");
- }
- template<typename T>
- typename PoolAllocator<T>::ItemBlock& PoolAllocator<T>::CreateNewBlock()
- {
- const UINT newBlockCapacity = m_ItemBlocks.empty() ?
- m_FirstBlockCapacity : m_ItemBlocks.back().Capacity * 3 / 2;
- const ItemBlock newBlock = {
- D3D12MA_NEW_ARRAY(m_AllocationCallbacks, Item, newBlockCapacity),
- newBlockCapacity,
- 0 };
- m_ItemBlocks.push_back(newBlock);
- // Setup singly-linked list of all free items in this block.
- for(UINT i = 0; i < newBlockCapacity - 1; ++i)
- {
- newBlock.pItems[i].NextFreeIndex = i + 1;
- }
- newBlock.pItems[newBlockCapacity - 1].NextFreeIndex = UINT32_MAX;
- return m_ItemBlocks.back();
- }
- #endif // _D3D12MA_POOL_ALLOCATOR_FUNCTIONS
- #endif // _D3D12MA_POOL_ALLOCATOR
- #ifndef _D3D12MA_LIST
- /*
- Doubly linked list, with elements allocated out of PoolAllocator.
- Has custom interface, as well as STL-style interface, including iterator and
- const_iterator.
- */
- template<typename T>
- class List
- {
- D3D12MA_CLASS_NO_COPY(List)
- public:
- struct Item
- {
- Item* pPrev;
- Item* pNext;
- T Value;
- };
- class reverse_iterator;
- class const_reverse_iterator;
- class iterator
- {
- friend class List<T>;
- friend class const_iterator;
- public:
- iterator() = default;
- iterator(const reverse_iterator& src)
- : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
- T& operator*() const;
- T* operator->() const;
- iterator& operator++();
- iterator& operator--();
- iterator operator++(int);
- iterator operator--(int);
- bool operator==(const iterator& rhs) const;
- bool operator!=(const iterator& rhs) const;
- private:
- List<T>* m_pList = NULL;
- Item* m_pItem = NULL;
- iterator(List<T>* pList, Item* pItem) : m_pList(pList), m_pItem(pItem) {}
- };
- class reverse_iterator
- {
- friend class List<T>;
- friend class const_reverse_iterator;
- public:
- reverse_iterator() = default;
- reverse_iterator(const iterator& src)
- : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
- T& operator*() const;
- T* operator->() const;
- reverse_iterator& operator++();
- reverse_iterator& operator--();
- reverse_iterator operator++(int);
- reverse_iterator operator--(int);
- bool operator==(const reverse_iterator& rhs) const;
- bool operator!=(const reverse_iterator& rhs) const;
- private:
- List<T>* m_pList = NULL;
- Item* m_pItem = NULL;
- reverse_iterator(List<T>* pList, Item* pItem)
- : m_pList(pList), m_pItem(pItem) {}
- };
- class const_iterator
- {
- friend class List<T>;
- public:
- const_iterator() = default;
- const_iterator(const iterator& src)
- : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
- const_iterator(const reverse_iterator& src)
- : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
- const_iterator(const const_reverse_iterator& src)
- : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
- iterator dropConst() const;
- const T& operator*() const;
- const T* operator->() const;
- const_iterator& operator++();
- const_iterator& operator--();
- const_iterator operator++(int);
- const_iterator operator--(int);
- bool operator==(const const_iterator& rhs) const;
- bool operator!=(const const_iterator& rhs) const;
- private:
- const List<T>* m_pList = NULL;
- const Item* m_pItem = NULL;
- const_iterator(const List<T>* pList, const Item* pItem)
- : m_pList(pList), m_pItem(pItem) {}
- };
- class const_reverse_iterator
- {
- friend class List<T>;
- public:
- const_reverse_iterator() = default;
- const_reverse_iterator(const iterator& src)
- : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
- const_reverse_iterator(const reverse_iterator& src)
- : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
- const_reverse_iterator(const const_iterator& src)
- : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
- reverse_iterator dropConst() const;
- const T& operator*() const;
- const T* operator->() const;
- const_reverse_iterator& operator++();
- const_reverse_iterator& operator--();
- const_reverse_iterator operator++(int);
- const_reverse_iterator operator--(int);
- bool operator==(const const_reverse_iterator& rhs) const;
- bool operator!=(const const_reverse_iterator& rhs) const;
- private:
- const List<T>* m_pList = NULL;
- const Item* m_pItem = NULL;
- const_reverse_iterator(const List<T>* pList, const Item* pItem)
- : m_pList(pList), m_pItem(pItem) {}
- };
- // allocationCallbacks externally owned, must outlive this object.
- List(const ALLOCATION_CALLBACKS& allocationCallbacks);
- // Intentionally not calling Clear, because that would be unnecessary
- // computations to return all items to m_ItemAllocator as free.
- ~List() = default;
-
- size_t GetCount() const { return m_Count; }
- bool IsEmpty() const { return m_Count == 0; }
- Item* Front() { return m_pFront; }
- const Item* Front() const { return m_pFront; }
- Item* Back() { return m_pBack; }
- const Item* Back() const { return m_pBack; }
- bool empty() const { return IsEmpty(); }
- size_t size() const { return GetCount(); }
- void push_back(const T& value) { PushBack(value); }
- iterator insert(iterator it, const T& value) { return iterator(this, InsertBefore(it.m_pItem, value)); }
- void clear() { Clear(); }
- void erase(iterator it) { Remove(it.m_pItem); }
- iterator begin() { return iterator(this, Front()); }
- iterator end() { return iterator(this, NULL); }
- reverse_iterator rbegin() { return reverse_iterator(this, Back()); }
- reverse_iterator rend() { return reverse_iterator(this, NULL); }
- const_iterator cbegin() const { return const_iterator(this, Front()); }
- const_iterator cend() const { return const_iterator(this, NULL); }
- const_iterator begin() const { return cbegin(); }
- const_iterator end() const { return cend(); }
- const_reverse_iterator crbegin() const { return const_reverse_iterator(this, Back()); }
- const_reverse_iterator crend() const { return const_reverse_iterator(this, NULL); }
- const_reverse_iterator rbegin() const { return crbegin(); }
- const_reverse_iterator rend() const { return crend(); }
- Item* PushBack();
- Item* PushFront();
- Item* PushBack(const T& value);
- Item* PushFront(const T& value);
- void PopBack();
- void PopFront();
- // Item can be null - it means PushBack.
- Item* InsertBefore(Item* pItem);
- // Item can be null - it means PushFront.
- Item* InsertAfter(Item* pItem);
- Item* InsertBefore(Item* pItem, const T& value);
- Item* InsertAfter(Item* pItem, const T& value);
- void Clear();
- void Remove(Item* pItem);
- private:
- const ALLOCATION_CALLBACKS& m_AllocationCallbacks;
- PoolAllocator<Item> m_ItemAllocator;
- Item* m_pFront;
- Item* m_pBack;
- size_t m_Count;
- };
- #ifndef _D3D12MA_LIST_ITERATOR_FUNCTIONS
- template<typename T>
- T& List<T>::iterator::operator*() const
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- return m_pItem->Value;
- }
- template<typename T>
- T* List<T>::iterator::operator->() const
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- return &m_pItem->Value;
- }
- template<typename T>
- typename List<T>::iterator& List<T>::iterator::operator++()
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- m_pItem = m_pItem->pNext;
- return *this;
- }
- template<typename T>
- typename List<T>::iterator& List<T>::iterator::operator--()
- {
- if (m_pItem != NULL)
- {
- m_pItem = m_pItem->pPrev;
- }
- else
- {
- D3D12MA_HEAVY_ASSERT(!m_pList->IsEmpty());
- m_pItem = m_pList->Back();
- }
- return *this;
- }
- template<typename T>
- typename List<T>::iterator List<T>::iterator::operator++(int)
- {
- iterator result = *this;
- ++* this;
- return result;
- }
- template<typename T>
- typename List<T>::iterator List<T>::iterator::operator--(int)
- {
- iterator result = *this;
- --* this;
- return result;
- }
- template<typename T>
- bool List<T>::iterator::operator==(const iterator& rhs) const
- {
- D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
- return m_pItem == rhs.m_pItem;
- }
- template<typename T>
- bool List<T>::iterator::operator!=(const iterator& rhs) const
- {
- D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
- return m_pItem != rhs.m_pItem;
- }
- #endif // _D3D12MA_LIST_ITERATOR_FUNCTIONS
- #ifndef _D3D12MA_LIST_REVERSE_ITERATOR_FUNCTIONS
- template<typename T>
- T& List<T>::reverse_iterator::operator*() const
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- return m_pItem->Value;
- }
- template<typename T>
- T* List<T>::reverse_iterator::operator->() const
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- return &m_pItem->Value;
- }
- template<typename T>
- typename List<T>::reverse_iterator& List<T>::reverse_iterator::operator++()
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- m_pItem = m_pItem->pPrev;
- return *this;
- }
- template<typename T>
- typename List<T>::reverse_iterator& List<T>::reverse_iterator::operator--()
- {
- if (m_pItem != NULL)
- {
- m_pItem = m_pItem->pNext;
- }
- else
- {
- D3D12MA_HEAVY_ASSERT(!m_pList->IsEmpty());
- m_pItem = m_pList->Front();
- }
- return *this;
- }
- template<typename T>
- typename List<T>::reverse_iterator List<T>::reverse_iterator::operator++(int)
- {
- reverse_iterator result = *this;
- ++* this;
- return result;
- }
- template<typename T>
- typename List<T>::reverse_iterator List<T>::reverse_iterator::operator--(int)
- {
- reverse_iterator result = *this;
- --* this;
- return result;
- }
- template<typename T>
- bool List<T>::reverse_iterator::operator==(const reverse_iterator& rhs) const
- {
- D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
- return m_pItem == rhs.m_pItem;
- }
- template<typename T>
- bool List<T>::reverse_iterator::operator!=(const reverse_iterator& rhs) const
- {
- D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
- return m_pItem != rhs.m_pItem;
- }
- #endif // _D3D12MA_LIST_REVERSE_ITERATOR_FUNCTIONS
- #ifndef _D3D12MA_LIST_CONST_ITERATOR_FUNCTIONS
- template<typename T>
- typename List<T>::iterator List<T>::const_iterator::dropConst() const
- {
- return iterator(const_cast<List<T>*>(m_pList), const_cast<Item*>(m_pItem));
- }
- template<typename T>
- const T& List<T>::const_iterator::operator*() const
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- return m_pItem->Value;
- }
- template<typename T>
- const T* List<T>::const_iterator::operator->() const
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- return &m_pItem->Value;
- }
- template<typename T>
- typename List<T>::const_iterator& List<T>::const_iterator::operator++()
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- m_pItem = m_pItem->pNext;
- return *this;
- }
- template<typename T>
- typename List<T>::const_iterator& List<T>::const_iterator::operator--()
- {
- if (m_pItem != NULL)
- {
- m_pItem = m_pItem->pPrev;
- }
- else
- {
- D3D12MA_HEAVY_ASSERT(!m_pList->IsEmpty());
- m_pItem = m_pList->Back();
- }
- return *this;
- }
- template<typename T>
- typename List<T>::const_iterator List<T>::const_iterator::operator++(int)
- {
- const_iterator result = *this;
- ++* this;
- return result;
- }
- template<typename T>
- typename List<T>::const_iterator List<T>::const_iterator::operator--(int)
- {
- const_iterator result = *this;
- --* this;
- return result;
- }
- template<typename T>
- bool List<T>::const_iterator::operator==(const const_iterator& rhs) const
- {
- D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
- return m_pItem == rhs.m_pItem;
- }
- template<typename T>
- bool List<T>::const_iterator::operator!=(const const_iterator& rhs) const
- {
- D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
- return m_pItem != rhs.m_pItem;
- }
- #endif // _D3D12MA_LIST_CONST_ITERATOR_FUNCTIONS
- #ifndef _D3D12MA_LIST_CONST_REVERSE_ITERATOR_FUNCTIONS
- template<typename T>
- typename List<T>::reverse_iterator List<T>::const_reverse_iterator::dropConst() const
- {
- return reverse_iterator(const_cast<List<T>*>(m_pList), const_cast<Item*>(m_pItem));
- }
- template<typename T>
- const T& List<T>::const_reverse_iterator::operator*() const
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- return m_pItem->Value;
- }
- template<typename T>
- const T* List<T>::const_reverse_iterator::operator->() const
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- return &m_pItem->Value;
- }
- template<typename T>
- typename List<T>::const_reverse_iterator& List<T>::const_reverse_iterator::operator++()
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- m_pItem = m_pItem->pPrev;
- return *this;
- }
- template<typename T>
- typename List<T>::const_reverse_iterator& List<T>::const_reverse_iterator::operator--()
- {
- if (m_pItem != NULL)
- {
- m_pItem = m_pItem->pNext;
- }
- else
- {
- D3D12MA_HEAVY_ASSERT(!m_pList->IsEmpty());
- m_pItem = m_pList->Front();
- }
- return *this;
- }
- template<typename T>
- typename List<T>::const_reverse_iterator List<T>::const_reverse_iterator::operator++(int)
- {
- const_reverse_iterator result = *this;
- ++* this;
- return result;
- }
- template<typename T>
- typename List<T>::const_reverse_iterator List<T>::const_reverse_iterator::operator--(int)
- {
- const_reverse_iterator result = *this;
- --* this;
- return result;
- }
- template<typename T>
- bool List<T>::const_reverse_iterator::operator==(const const_reverse_iterator& rhs) const
- {
- D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
- return m_pItem == rhs.m_pItem;
- }
- template<typename T>
- bool List<T>::const_reverse_iterator::operator!=(const const_reverse_iterator& rhs) const
- {
- D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
- return m_pItem != rhs.m_pItem;
- }
- #endif // _D3D12MA_LIST_CONST_REVERSE_ITERATOR_FUNCTIONS
- #ifndef _D3D12MA_LIST_FUNCTIONS
- template<typename T>
- List<T>::List(const ALLOCATION_CALLBACKS& allocationCallbacks)
- : m_AllocationCallbacks(allocationCallbacks),
- m_ItemAllocator(allocationCallbacks, 128),
- m_pFront(NULL),
- m_pBack(NULL),
- m_Count(0) {}
- template<typename T>
- void List<T>::Clear()
- {
- if(!IsEmpty())
- {
- Item* pItem = m_pBack;
- while(pItem != NULL)
- {
- Item* const pPrevItem = pItem->pPrev;
- m_ItemAllocator.Free(pItem);
- pItem = pPrevItem;
- }
- m_pFront = NULL;
- m_pBack = NULL;
- m_Count = 0;
- }
- }
- template<typename T>
- typename List<T>::Item* List<T>::PushBack()
- {
- Item* const pNewItem = m_ItemAllocator.Alloc();
- pNewItem->pNext = NULL;
- if(IsEmpty())
- {
- pNewItem->pPrev = NULL;
- m_pFront = pNewItem;
- m_pBack = pNewItem;
- m_Count = 1;
- }
- else
- {
- pNewItem->pPrev = m_pBack;
- m_pBack->pNext = pNewItem;
- m_pBack = pNewItem;
- ++m_Count;
- }
- return pNewItem;
- }
- template<typename T>
- typename List<T>::Item* List<T>::PushFront()
- {
- Item* const pNewItem = m_ItemAllocator.Alloc();
- pNewItem->pPrev = NULL;
- if(IsEmpty())
- {
- pNewItem->pNext = NULL;
- m_pFront = pNewItem;
- m_pBack = pNewItem;
- m_Count = 1;
- }
- else
- {
- pNewItem->pNext = m_pFront;
- m_pFront->pPrev = pNewItem;
- m_pFront = pNewItem;
- ++m_Count;
- }
- return pNewItem;
- }
- template<typename T>
- typename List<T>::Item* List<T>::PushBack(const T& value)
- {
- Item* const pNewItem = PushBack();
- pNewItem->Value = value;
- return pNewItem;
- }
- template<typename T>
- typename List<T>::Item* List<T>::PushFront(const T& value)
- {
- Item* const pNewItem = PushFront();
- pNewItem->Value = value;
- return pNewItem;
- }
- template<typename T>
- void List<T>::PopBack()
- {
- D3D12MA_HEAVY_ASSERT(m_Count > 0);
- Item* const pBackItem = m_pBack;
- Item* const pPrevItem = pBackItem->pPrev;
- if(pPrevItem != NULL)
- {
- pPrevItem->pNext = NULL;
- }
- m_pBack = pPrevItem;
- m_ItemAllocator.Free(pBackItem);
- --m_Count;
- }
- template<typename T>
- void List<T>::PopFront()
- {
- D3D12MA_HEAVY_ASSERT(m_Count > 0);
- Item* const pFrontItem = m_pFront;
- Item* const pNextItem = pFrontItem->pNext;
- if(pNextItem != NULL)
- {
- pNextItem->pPrev = NULL;
- }
- m_pFront = pNextItem;
- m_ItemAllocator.Free(pFrontItem);
- --m_Count;
- }
- template<typename T>
- void List<T>::Remove(Item* pItem)
- {
- D3D12MA_HEAVY_ASSERT(pItem != NULL);
- D3D12MA_HEAVY_ASSERT(m_Count > 0);
- if(pItem->pPrev != NULL)
- {
- pItem->pPrev->pNext = pItem->pNext;
- }
- else
- {
- D3D12MA_HEAVY_ASSERT(m_pFront == pItem);
- m_pFront = pItem->pNext;
- }
- if(pItem->pNext != NULL)
- {
- pItem->pNext->pPrev = pItem->pPrev;
- }
- else
- {
- D3D12MA_HEAVY_ASSERT(m_pBack == pItem);
- m_pBack = pItem->pPrev;
- }
- m_ItemAllocator.Free(pItem);
- --m_Count;
- }
- template<typename T>
- typename List<T>::Item* List<T>::InsertBefore(Item* pItem)
- {
- if(pItem != NULL)
- {
- Item* const prevItem = pItem->pPrev;
- Item* const newItem = m_ItemAllocator.Alloc();
- newItem->pPrev = prevItem;
- newItem->pNext = pItem;
- pItem->pPrev = newItem;
- if(prevItem != NULL)
- {
- prevItem->pNext = newItem;
- }
- else
- {
- D3D12MA_HEAVY_ASSERT(m_pFront == pItem);
- m_pFront = newItem;
- }
- ++m_Count;
- return newItem;
- }
- else
- {
- return PushBack();
- }
- }
- template<typename T>
- typename List<T>::Item* List<T>::InsertAfter(Item* pItem)
- {
- if(pItem != NULL)
- {
- Item* const nextItem = pItem->pNext;
- Item* const newItem = m_ItemAllocator.Alloc();
- newItem->pNext = nextItem;
- newItem->pPrev = pItem;
- pItem->pNext = newItem;
- if(nextItem != NULL)
- {
- nextItem->pPrev = newItem;
- }
- else
- {
- D3D12MA_HEAVY_ASSERT(m_pBack == pItem);
- m_pBack = newItem;
- }
- ++m_Count;
- return newItem;
- }
- else
- return PushFront();
- }
- template<typename T>
- typename List<T>::Item* List<T>::InsertBefore(Item* pItem, const T& value)
- {
- Item* const newItem = InsertBefore(pItem);
- newItem->Value = value;
- return newItem;
- }
- template<typename T>
- typename List<T>::Item* List<T>::InsertAfter(Item* pItem, const T& value)
- {
- Item* const newItem = InsertAfter(pItem);
- newItem->Value = value;
- return newItem;
- }
- #endif // _D3D12MA_LIST_FUNCTIONS
- #endif // _D3D12MA_LIST
- #ifndef _D3D12MA_INTRUSIVE_LINKED_LIST
- /*
- Expected interface of ItemTypeTraits:
- struct MyItemTypeTraits
- {
- using ItemType = MyItem;
- static ItemType* GetPrev(const ItemType* item) { return item->myPrevPtr; }
- static ItemType* GetNext(const ItemType* item) { return item->myNextPtr; }
- static ItemType*& AccessPrev(ItemType* item) { return item->myPrevPtr; }
- static ItemType*& AccessNext(ItemType* item) { return item->myNextPtr; }
- };
- */
- template<typename ItemTypeTraits>
- class IntrusiveLinkedList
- {
- public:
- using ItemType = typename ItemTypeTraits::ItemType;
- static ItemType* GetPrev(const ItemType* item) { return ItemTypeTraits::GetPrev(item); }
- static ItemType* GetNext(const ItemType* item) { return ItemTypeTraits::GetNext(item); }
- // Movable, not copyable.
- IntrusiveLinkedList() = default;
- IntrusiveLinkedList(const IntrusiveLinkedList&) = delete;
- IntrusiveLinkedList(IntrusiveLinkedList&& src);
- IntrusiveLinkedList& operator=(const IntrusiveLinkedList&) = delete;
- IntrusiveLinkedList& operator=(IntrusiveLinkedList&& src);
- ~IntrusiveLinkedList() { D3D12MA_HEAVY_ASSERT(IsEmpty()); }
- size_t GetCount() const { return m_Count; }
- bool IsEmpty() const { return m_Count == 0; }
- ItemType* Front() { return m_Front; }
- ItemType* Back() { return m_Back; }
- const ItemType* Front() const { return m_Front; }
- const ItemType* Back() const { return m_Back; }
- void PushBack(ItemType* item);
- void PushFront(ItemType* item);
- ItemType* PopBack();
- ItemType* PopFront();
- // MyItem can be null - it means PushBack.
- void InsertBefore(ItemType* existingItem, ItemType* newItem);
- // MyItem can be null - it means PushFront.
- void InsertAfter(ItemType* existingItem, ItemType* newItem);
- void Remove(ItemType* item);
- void RemoveAll();
- private:
- ItemType* m_Front = NULL;
- ItemType* m_Back = NULL;
- size_t m_Count = 0;
- };
- #ifndef _D3D12MA_INTRUSIVE_LINKED_LIST_FUNCTIONS
- template<typename ItemTypeTraits>
- IntrusiveLinkedList<ItemTypeTraits>::IntrusiveLinkedList(IntrusiveLinkedList&& src)
- : m_Front(src.m_Front), m_Back(src.m_Back), m_Count(src.m_Count)
- {
- src.m_Front = src.m_Back = NULL;
- src.m_Count = 0;
- }
- template<typename ItemTypeTraits>
- IntrusiveLinkedList<ItemTypeTraits>& IntrusiveLinkedList<ItemTypeTraits>::operator=(IntrusiveLinkedList&& src)
- {
- if (&src != this)
- {
- D3D12MA_HEAVY_ASSERT(IsEmpty());
- m_Front = src.m_Front;
- m_Back = src.m_Back;
- m_Count = src.m_Count;
- src.m_Front = src.m_Back = NULL;
- src.m_Count = 0;
- }
- return *this;
- }
- template<typename ItemTypeTraits>
- void IntrusiveLinkedList<ItemTypeTraits>::PushBack(ItemType* item)
- {
- D3D12MA_HEAVY_ASSERT(ItemTypeTraits::GetPrev(item) == NULL && ItemTypeTraits::GetNext(item) == NULL);
- if (IsEmpty())
- {
- m_Front = item;
- m_Back = item;
- m_Count = 1;
- }
- else
- {
- ItemTypeTraits::AccessPrev(item) = m_Back;
- ItemTypeTraits::AccessNext(m_Back) = item;
- m_Back = item;
- ++m_Count;
- }
- }
- template<typename ItemTypeTraits>
- void IntrusiveLinkedList<ItemTypeTraits>::PushFront(ItemType* item)
- {
- D3D12MA_HEAVY_ASSERT(ItemTypeTraits::GetPrev(item) == NULL && ItemTypeTraits::GetNext(item) == NULL);
- if (IsEmpty())
- {
- m_Front = item;
- m_Back = item;
- m_Count = 1;
- }
- else
- {
- ItemTypeTraits::AccessNext(item) = m_Front;
- ItemTypeTraits::AccessPrev(m_Front) = item;
- m_Front = item;
- ++m_Count;
- }
- }
- template<typename ItemTypeTraits>
- typename IntrusiveLinkedList<ItemTypeTraits>::ItemType* IntrusiveLinkedList<ItemTypeTraits>::PopBack()
- {
- D3D12MA_HEAVY_ASSERT(m_Count > 0);
- ItemType* const backItem = m_Back;
- ItemType* const prevItem = ItemTypeTraits::GetPrev(backItem);
- if (prevItem != NULL)
- {
- ItemTypeTraits::AccessNext(prevItem) = NULL;
- }
- m_Back = prevItem;
- --m_Count;
- ItemTypeTraits::AccessPrev(backItem) = NULL;
- ItemTypeTraits::AccessNext(backItem) = NULL;
- return backItem;
- }
- template<typename ItemTypeTraits>
- typename IntrusiveLinkedList<ItemTypeTraits>::ItemType* IntrusiveLinkedList<ItemTypeTraits>::PopFront()
- {
- D3D12MA_HEAVY_ASSERT(m_Count > 0);
- ItemType* const frontItem = m_Front;
- ItemType* const nextItem = ItemTypeTraits::GetNext(frontItem);
- if (nextItem != NULL)
- {
- ItemTypeTraits::AccessPrev(nextItem) = NULL;
- }
- m_Front = nextItem;
- --m_Count;
- ItemTypeTraits::AccessPrev(frontItem) = NULL;
- ItemTypeTraits::AccessNext(frontItem) = NULL;
- return frontItem;
- }
- template<typename ItemTypeTraits>
- void IntrusiveLinkedList<ItemTypeTraits>::InsertBefore(ItemType* existingItem, ItemType* newItem)
- {
- D3D12MA_HEAVY_ASSERT(newItem != NULL && ItemTypeTraits::GetPrev(newItem) == NULL && ItemTypeTraits::GetNext(newItem) == NULL);
- if (existingItem != NULL)
- {
- ItemType* const prevItem = ItemTypeTraits::GetPrev(existingItem);
- ItemTypeTraits::AccessPrev(newItem) = prevItem;
- ItemTypeTraits::AccessNext(newItem) = existingItem;
- ItemTypeTraits::AccessPrev(existingItem) = newItem;
- if (prevItem != NULL)
- {
- ItemTypeTraits::AccessNext(prevItem) = newItem;
- }
- else
- {
- D3D12MA_HEAVY_ASSERT(m_Front == existingItem);
- m_Front = newItem;
- }
- ++m_Count;
- }
- else
- PushBack(newItem);
- }
- template<typename ItemTypeTraits>
- void IntrusiveLinkedList<ItemTypeTraits>::InsertAfter(ItemType* existingItem, ItemType* newItem)
- {
- D3D12MA_HEAVY_ASSERT(newItem != NULL && ItemTypeTraits::GetPrev(newItem) == NULL && ItemTypeTraits::GetNext(newItem) == NULL);
- if (existingItem != NULL)
- {
- ItemType* const nextItem = ItemTypeTraits::GetNext(existingItem);
- ItemTypeTraits::AccessNext(newItem) = nextItem;
- ItemTypeTraits::AccessPrev(newItem) = existingItem;
- ItemTypeTraits::AccessNext(existingItem) = newItem;
- if (nextItem != NULL)
- {
- ItemTypeTraits::AccessPrev(nextItem) = newItem;
- }
- else
- {
- D3D12MA_HEAVY_ASSERT(m_Back == existingItem);
- m_Back = newItem;
- }
- ++m_Count;
- }
- else
- return PushFront(newItem);
- }
- template<typename ItemTypeTraits>
- void IntrusiveLinkedList<ItemTypeTraits>::Remove(ItemType* item)
- {
- D3D12MA_HEAVY_ASSERT(item != NULL && m_Count > 0);
- if (ItemTypeTraits::GetPrev(item) != NULL)
- {
- ItemTypeTraits::AccessNext(ItemTypeTraits::AccessPrev(item)) = ItemTypeTraits::GetNext(item);
- }
- else
- {
- D3D12MA_HEAVY_ASSERT(m_Front == item);
- m_Front = ItemTypeTraits::GetNext(item);
- }
- if (ItemTypeTraits::GetNext(item) != NULL)
- {
- ItemTypeTraits::AccessPrev(ItemTypeTraits::AccessNext(item)) = ItemTypeTraits::GetPrev(item);
- }
- else
- {
- D3D12MA_HEAVY_ASSERT(m_Back == item);
- m_Back = ItemTypeTraits::GetPrev(item);
- }
- ItemTypeTraits::AccessPrev(item) = NULL;
- ItemTypeTraits::AccessNext(item) = NULL;
- --m_Count;
- }
- template<typename ItemTypeTraits>
- void IntrusiveLinkedList<ItemTypeTraits>::RemoveAll()
- {
- if (!IsEmpty())
- {
- ItemType* item = m_Back;
- while (item != NULL)
- {
- ItemType* const prevItem = ItemTypeTraits::AccessPrev(item);
- ItemTypeTraits::AccessPrev(item) = NULL;
- ItemTypeTraits::AccessNext(item) = NULL;
- item = prevItem;
- }
- m_Front = NULL;
- m_Back = NULL;
- m_Count = 0;
- }
- }
- #endif // _D3D12MA_INTRUSIVE_LINKED_LIST_FUNCTIONS
- #endif // _D3D12MA_INTRUSIVE_LINKED_LIST
- #ifndef _D3D12MA_ALLOCATION_OBJECT_ALLOCATOR
- /*
- Thread-safe wrapper over PoolAllocator free list, for allocation of Allocation objects.
- */
- class AllocationObjectAllocator
- {
- D3D12MA_CLASS_NO_COPY(AllocationObjectAllocator);
- public:
- AllocationObjectAllocator(const ALLOCATION_CALLBACKS& allocationCallbacks)
- : m_Allocator(allocationCallbacks, 1024) {}
- template<typename... Types>
- Allocation* Allocate(Types... args);
- void Free(Allocation* alloc);
- private:
- D3D12MA_MUTEX m_Mutex;
- PoolAllocator<Allocation> m_Allocator;
- };
- #ifndef _D3D12MA_ALLOCATION_OBJECT_ALLOCATOR_FUNCTIONS
- template<typename... Types>
- Allocation* AllocationObjectAllocator::Allocate(Types... args)
- {
- MutexLock mutexLock(m_Mutex);
- return m_Allocator.Alloc(std::forward<Types>(args)...);
- }
- void AllocationObjectAllocator::Free(Allocation* alloc)
- {
- MutexLock mutexLock(m_Mutex);
- m_Allocator.Free(alloc);
- }
- #endif // _D3D12MA_ALLOCATION_OBJECT_ALLOCATOR_FUNCTIONS
- #endif // _D3D12MA_ALLOCATION_OBJECT_ALLOCATOR
- #ifndef _D3D12MA_SUBALLOCATION
- /*
- Represents a region of NormalBlock that is either assigned and returned as
- allocated memory block or free.
- */
- struct Suballocation
- {
- UINT64 offset;
- UINT64 size;
- void* privateData;
- SuballocationType type;
- };
- using SuballocationList = List<Suballocation>;
- // Comparator for offsets.
- struct SuballocationOffsetLess
- {
- bool operator()(const Suballocation& lhs, const Suballocation& rhs) const
- {
- return lhs.offset < rhs.offset;
- }
- };
- struct SuballocationOffsetGreater
- {
- bool operator()(const Suballocation& lhs, const Suballocation& rhs) const
- {
- return lhs.offset > rhs.offset;
- }
- };
- struct SuballocationItemSizeLess
- {
- bool operator()(const SuballocationList::iterator lhs, const SuballocationList::iterator rhs) const
- {
- return lhs->size < rhs->size;
- }
- bool operator()(const SuballocationList::iterator lhs, UINT64 rhsSize) const
- {
- return lhs->size < rhsSize;
- }
- };
- #endif // _D3D12MA_SUBALLOCATION
- #ifndef _D3D12MA_ALLOCATION_REQUEST
- /*
- Parameters of planned allocation inside a NormalBlock.
- */
- struct AllocationRequest
- {
- AllocHandle allocHandle;
- UINT64 size;
- UINT64 algorithmData;
- UINT64 sumFreeSize; // Sum size of free items that overlap with proposed allocation.
- UINT64 sumItemSize; // Sum size of items to make lost that overlap with proposed allocation.
- SuballocationList::iterator item;
- BOOL zeroInitialized = FALSE; // TODO Implement proper handling in TLSF and Linear, using ZeroInitializedRange class.
- };
- #endif // _D3D12MA_ALLOCATION_REQUEST
- #ifndef _D3D12MA_ZERO_INITIALIZED_RANGE
- /*
- Keeps track of the range of bytes that are surely initialized with zeros.
- Everything outside of it is considered uninitialized memory that may contain
- garbage data.
- The range is left-inclusive.
- */
- class ZeroInitializedRange
- {
- public:
- void Reset(UINT64 size);
- BOOL IsRangeZeroInitialized(UINT64 beg, UINT64 end) const;
- void MarkRangeAsUsed(UINT64 usedBeg, UINT64 usedEnd);
- private:
- UINT64 m_ZeroBeg = 0, m_ZeroEnd = 0;
- };
- #ifndef _D3D12MA_ZERO_INITIALIZED_RANGE_FUNCTIONS
- void ZeroInitializedRange::Reset(UINT64 size)
- {
- D3D12MA_ASSERT(size > 0);
- m_ZeroBeg = 0;
- m_ZeroEnd = size;
- }
- BOOL ZeroInitializedRange::IsRangeZeroInitialized(UINT64 beg, UINT64 end) const
- {
- D3D12MA_ASSERT(beg < end);
- return m_ZeroBeg <= beg && end <= m_ZeroEnd;
- }
- void ZeroInitializedRange::MarkRangeAsUsed(UINT64 usedBeg, UINT64 usedEnd)
- {
- D3D12MA_ASSERT(usedBeg < usedEnd);
- // No new bytes marked.
- if (usedEnd <= m_ZeroBeg || m_ZeroEnd <= usedBeg)
- {
- return;
- }
- // All bytes marked.
- if (usedBeg <= m_ZeroBeg && m_ZeroEnd <= usedEnd)
- {
- m_ZeroBeg = m_ZeroEnd = 0;
- }
- // Some bytes marked.
- else
- {
- const UINT64 remainingZeroBefore = usedBeg > m_ZeroBeg ? usedBeg - m_ZeroBeg : 0;
- const UINT64 remainingZeroAfter = usedEnd < m_ZeroEnd ? m_ZeroEnd - usedEnd : 0;
- D3D12MA_ASSERT(remainingZeroBefore > 0 || remainingZeroAfter > 0);
- if (remainingZeroBefore > remainingZeroAfter)
- {
- m_ZeroEnd = usedBeg;
- }
- else
- {
- m_ZeroBeg = usedEnd;
- }
- }
- }
- #endif // _D3D12MA_ZERO_INITIALIZED_RANGE_FUNCTIONS
- #endif // _D3D12MA_ZERO_INITIALIZED_RANGE
- #ifndef _D3D12MA_BLOCK_METADATA
- /*
- Data structure used for bookkeeping of allocations and unused ranges of memory
- in a single ID3D12Heap memory block.
- */
- class BlockMetadata
- {
- public:
- BlockMetadata(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual);
- virtual ~BlockMetadata() = default;
- virtual void Init(UINT64 size) { m_Size = size; }
- // Validates all data structures inside this object. If not valid, returns false.
- virtual bool Validate() const = 0;
- UINT64 GetSize() const { return m_Size; }
- bool IsVirtual() const { return m_IsVirtual; }
- virtual size_t GetAllocationCount() const = 0;
- virtual size_t GetFreeRegionsCount() const = 0;
- virtual UINT64 GetSumFreeSize() const = 0;
- virtual UINT64 GetAllocationOffset(AllocHandle allocHandle) const = 0;
- // Returns true if this block is empty - contains only single free suballocation.
- virtual bool IsEmpty() const = 0;
- virtual void GetAllocationInfo(AllocHandle allocHandle, VIRTUAL_ALLOCATION_INFO& outInfo) const = 0;
- // Tries to find a place for suballocation with given parameters inside this block.
- // If succeeded, fills pAllocationRequest and returns true.
- // If failed, returns false.
- virtual bool CreateAllocationRequest(
- UINT64 allocSize,
- UINT64 allocAlignment,
- bool upperAddress,
- UINT32 strategy,
- AllocationRequest* pAllocationRequest) = 0;
- // Makes actual allocation based on request. Request must already be checked and valid.
- virtual void Alloc(
- const AllocationRequest& request,
- UINT64 allocSize,
- void* PrivateData) = 0;
- virtual void Free(AllocHandle allocHandle) = 0;
- // Frees all allocations.
- // Careful! Don't call it if there are Allocation objects owned by pPrivateData of of cleared allocations!
- virtual void Clear() = 0;
- virtual AllocHandle GetAllocationListBegin() const = 0;
- virtual AllocHandle GetNextAllocation(AllocHandle prevAlloc) const = 0;
- virtual UINT64 GetNextFreeRegionSize(AllocHandle alloc) const = 0;
- virtual void* GetAllocationPrivateData(AllocHandle allocHandle) const = 0;
- virtual void SetAllocationPrivateData(AllocHandle allocHandle, void* privateData) = 0;
- virtual void AddStatistics(Statistics& inoutStats) const = 0;
- virtual void AddDetailedStatistics(DetailedStatistics& inoutStats) const = 0;
- virtual void WriteAllocationInfoToJson(JsonWriter& json) const = 0;
- virtual void DebugLogAllAllocations() const = 0;
- protected:
- const ALLOCATION_CALLBACKS* GetAllocs() const { return m_pAllocationCallbacks; }
- UINT64 GetDebugMargin() const { return IsVirtual() ? 0 : D3D12MA_DEBUG_MARGIN; }
- void DebugLogAllocation(UINT64 offset, UINT64 size, void* privateData) const;
- void PrintDetailedMap_Begin(JsonWriter& json,
- UINT64 unusedBytes,
- size_t allocationCount,
- size_t unusedRangeCount) const;
- void PrintDetailedMap_Allocation(JsonWriter& json,
- UINT64 offset, UINT64 size, void* privateData) const;
- void PrintDetailedMap_UnusedRange(JsonWriter& json,
- UINT64 offset, UINT64 size) const;
- void PrintDetailedMap_End(JsonWriter& json) const;
- private:
- UINT64 m_Size;
- bool m_IsVirtual;
- const ALLOCATION_CALLBACKS* m_pAllocationCallbacks;
- D3D12MA_CLASS_NO_COPY(BlockMetadata);
- };
- #ifndef _D3D12MA_BLOCK_METADATA_FUNCTIONS
- BlockMetadata::BlockMetadata(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual)
- : m_Size(0),
- m_IsVirtual(isVirtual),
- m_pAllocationCallbacks(allocationCallbacks)
- {
- D3D12MA_ASSERT(allocationCallbacks);
- }
- void BlockMetadata::DebugLogAllocation(UINT64 offset, UINT64 size, void* privateData) const
- {
- if (IsVirtual())
- {
- D3D12MA_DEBUG_LOG(L"UNFREED VIRTUAL ALLOCATION; Offset: %llu; Size: %llu; PrivateData: %p", offset, size, privateData);
- }
- else
- {
- D3D12MA_ASSERT(privateData != NULL);
- Allocation* allocation = reinterpret_cast<Allocation*>(privateData);
- privateData = allocation->GetPrivateData();
- LPCWSTR name = allocation->GetName();
- D3D12MA_DEBUG_LOG(L"UNFREED ALLOCATION; Offset: %llu; Size: %llu; PrivateData: %p; Name: %s",
- offset, size, privateData, name ? name : L"D3D12MA_Empty");
- }
- }
- void BlockMetadata::PrintDetailedMap_Begin(JsonWriter& json,
- UINT64 unusedBytes, size_t allocationCount, size_t unusedRangeCount) const
- {
- json.WriteString(L"TotalBytes");
- json.WriteNumber(GetSize());
- json.WriteString(L"UnusedBytes");
- json.WriteNumber(unusedBytes);
- json.WriteString(L"Allocations");
- json.WriteNumber((UINT64)allocationCount);
- json.WriteString(L"UnusedRanges");
- json.WriteNumber((UINT64)unusedRangeCount);
- json.WriteString(L"Suballocations");
- json.BeginArray();
- }
- void BlockMetadata::PrintDetailedMap_Allocation(JsonWriter& json,
- UINT64 offset, UINT64 size, void* privateData) const
- {
- json.BeginObject(true);
- json.WriteString(L"Offset");
- json.WriteNumber(offset);
- if (IsVirtual())
- {
- json.WriteString(L"Size");
- json.WriteNumber(size);
- if (privateData)
- {
- json.WriteString(L"CustomData");
- json.WriteNumber((uintptr_t)privateData);
- }
- }
- else
- {
- const Allocation* const alloc = (const Allocation*)privateData;
- D3D12MA_ASSERT(alloc);
- json.AddAllocationToObject(*alloc);
- }
- json.EndObject();
- }
- void BlockMetadata::PrintDetailedMap_UnusedRange(JsonWriter& json,
- UINT64 offset, UINT64 size) const
- {
- json.BeginObject(true);
- json.WriteString(L"Offset");
- json.WriteNumber(offset);
- json.WriteString(L"Type");
- json.WriteString(L"FREE");
- json.WriteString(L"Size");
- json.WriteNumber(size);
- json.EndObject();
- }
- void BlockMetadata::PrintDetailedMap_End(JsonWriter& json) const
- {
- json.EndArray();
- }
- #endif // _D3D12MA_BLOCK_METADATA_FUNCTIONS
- #endif // _D3D12MA_BLOCK_METADATA
- #if 0
- #ifndef _D3D12MA_BLOCK_METADATA_GENERIC
- class BlockMetadata_Generic : public BlockMetadata
- {
- public:
- BlockMetadata_Generic(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual);
- virtual ~BlockMetadata_Generic() = default;
- size_t GetAllocationCount() const override { return m_Suballocations.size() - m_FreeCount; }
- UINT64 GetSumFreeSize() const override { return m_SumFreeSize; }
- UINT64 GetAllocationOffset(AllocHandle allocHandle) const override { return (UINT64)allocHandle - 1; }
- void Init(UINT64 size) override;
- bool Validate() const override;
- bool IsEmpty() const override;
- void GetAllocationInfo(AllocHandle allocHandle, VIRTUAL_ALLOCATION_INFO& outInfo) const override;
- bool CreateAllocationRequest(
- UINT64 allocSize,
- UINT64 allocAlignment,
- bool upperAddress,
- AllocationRequest* pAllocationRequest) override;
- void Alloc(
- const AllocationRequest& request,
- UINT64 allocSize,
- void* privateData) override;
- void Free(AllocHandle allocHandle) override;
- void Clear() override;
- void SetAllocationPrivateData(AllocHandle allocHandle, void* privateData) override;
- void AddStatistics(Statistics& inoutStats) const override;
- void AddDetailedStatistics(DetailedStatistics& inoutStats) const override;
- void WriteAllocationInfoToJson(JsonWriter& json) const override;
- private:
- UINT m_FreeCount;
- UINT64 m_SumFreeSize;
- SuballocationList m_Suballocations;
- // Suballocations that are free and have size greater than certain threshold.
- // Sorted by size, ascending.
- Vector<SuballocationList::iterator> m_FreeSuballocationsBySize;
- ZeroInitializedRange m_ZeroInitializedRange;
- SuballocationList::const_iterator FindAtOffset(UINT64 offset) const;
- bool ValidateFreeSuballocationList() const;
- // Checks if requested suballocation with given parameters can be placed in given pFreeSuballocItem.
- // If yes, fills pOffset and returns true. If no, returns false.
- bool CheckAllocation(
- UINT64 allocSize,
- UINT64 allocAlignment,
- SuballocationList::const_iterator suballocItem,
- AllocHandle* pAllocHandle,
- UINT64* pSumFreeSize,
- UINT64* pSumItemSize,
- BOOL *pZeroInitialized) const;
- // Given free suballocation, it merges it with following one, which must also be free.
- void MergeFreeWithNext(SuballocationList::iterator item);
- // Releases given suballocation, making it free.
- // Merges it with adjacent free suballocations if applicable.
- // Returns iterator to new free suballocation at this place.
- SuballocationList::iterator FreeSuballocation(SuballocationList::iterator suballocItem);
- // Given free suballocation, it inserts it into sorted list of
- // m_FreeSuballocationsBySize if it's suitable.
- void RegisterFreeSuballocation(SuballocationList::iterator item);
- // Given free suballocation, it removes it from sorted list of
- // m_FreeSuballocationsBySize if it's suitable.
- void UnregisterFreeSuballocation(SuballocationList::iterator item);
- D3D12MA_CLASS_NO_COPY(BlockMetadata_Generic)
- };
- #ifndef _D3D12MA_BLOCK_METADATA_GENERIC_FUNCTIONS
- BlockMetadata_Generic::BlockMetadata_Generic(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual)
- : BlockMetadata(allocationCallbacks, isVirtual),
- m_FreeCount(0),
- m_SumFreeSize(0),
- m_Suballocations(*allocationCallbacks),
- m_FreeSuballocationsBySize(*allocationCallbacks)
- {
- D3D12MA_ASSERT(allocationCallbacks);
- }
- void BlockMetadata_Generic::Init(UINT64 size)
- {
- BlockMetadata::Init(size);
- m_ZeroInitializedRange.Reset(size);
- m_FreeCount = 1;
- m_SumFreeSize = size;
- Suballocation suballoc = {};
- suballoc.offset = 0;
- suballoc.size = size;
- suballoc.type = SUBALLOCATION_TYPE_FREE;
- suballoc.privateData = NULL;
- D3D12MA_ASSERT(size > MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER);
- m_Suballocations.push_back(suballoc);
- SuballocationList::iterator suballocItem = m_Suballocations.end();
- --suballocItem;
- m_FreeSuballocationsBySize.push_back(suballocItem);
- }
- bool BlockMetadata_Generic::Validate() const
- {
- D3D12MA_VALIDATE(!m_Suballocations.empty());
- // Expected offset of new suballocation as calculated from previous ones.
- UINT64 calculatedOffset = 0;
- // Expected number of free suballocations as calculated from traversing their list.
- UINT calculatedFreeCount = 0;
- // Expected sum size of free suballocations as calculated from traversing their list.
- UINT64 calculatedSumFreeSize = 0;
- // Expected number of free suballocations that should be registered in
- // m_FreeSuballocationsBySize calculated from traversing their list.
- size_t freeSuballocationsToRegister = 0;
- // True if previous visited suballocation was free.
- bool prevFree = false;
- for (const auto& subAlloc : m_Suballocations)
- {
- // Actual offset of this suballocation doesn't match expected one.
- D3D12MA_VALIDATE(subAlloc.offset == calculatedOffset);
- const bool currFree = (subAlloc.type == SUBALLOCATION_TYPE_FREE);
- // Two adjacent free suballocations are invalid. They should be merged.
- D3D12MA_VALIDATE(!prevFree || !currFree);
- const Allocation* const alloc = (Allocation*)subAlloc.privateData;
- if (!IsVirtual())
- {
- D3D12MA_VALIDATE(currFree == (alloc == NULL));
- }
- if (currFree)
- {
- calculatedSumFreeSize += subAlloc.size;
- ++calculatedFreeCount;
- if (subAlloc.size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
- {
- ++freeSuballocationsToRegister;
- }
- // Margin required between allocations - every free space must be at least that large.
- D3D12MA_VALIDATE(subAlloc.size >= GetDebugMargin());
- }
- else
- {
- if (!IsVirtual())
- {
- D3D12MA_VALIDATE(alloc->GetOffset() == subAlloc.offset);
- D3D12MA_VALIDATE(alloc->GetSize() == subAlloc.size);
- }
- // Margin required between allocations - previous allocation must be free.
- D3D12MA_VALIDATE(GetDebugMargin() == 0 || prevFree);
- }
- calculatedOffset += subAlloc.size;
- prevFree = currFree;
- }
- // Number of free suballocations registered in m_FreeSuballocationsBySize doesn't
- // match expected one.
- D3D12MA_VALIDATE(m_FreeSuballocationsBySize.size() == freeSuballocationsToRegister);
- UINT64 lastSize = 0;
- for (size_t i = 0; i < m_FreeSuballocationsBySize.size(); ++i)
- {
- SuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[i];
- // Only free suballocations can be registered in m_FreeSuballocationsBySize.
- D3D12MA_VALIDATE(suballocItem->type == SUBALLOCATION_TYPE_FREE);
- // They must be sorted by size ascending.
- D3D12MA_VALIDATE(suballocItem->size >= lastSize);
- lastSize = suballocItem->size;
- }
- // Check if totals match calculacted values.
- D3D12MA_VALIDATE(ValidateFreeSuballocationList());
- D3D12MA_VALIDATE(calculatedOffset == GetSize());
- D3D12MA_VALIDATE(calculatedSumFreeSize == m_SumFreeSize);
- D3D12MA_VALIDATE(calculatedFreeCount == m_FreeCount);
- return true;
- }
- bool BlockMetadata_Generic::IsEmpty() const
- {
- return (m_Suballocations.size() == 1) && (m_FreeCount == 1);
- }
- void BlockMetadata_Generic::GetAllocationInfo(AllocHandle allocHandle, VIRTUAL_ALLOCATION_INFO& outInfo) const
- {
- Suballocation& suballoc = *FindAtOffset((UINT64)allocHandle - 1).dropConst();
- outInfo.Offset = suballoc.offset;
- outInfo.Size = suballoc.size;
- outInfo.pPrivateData = suballoc.privateData;
- }
- bool BlockMetadata_Generic::CreateAllocationRequest(
- UINT64 allocSize,
- UINT64 allocAlignment,
- bool upperAddress,
- AllocationRequest* pAllocationRequest)
- {
- D3D12MA_ASSERT(allocSize > 0);
- D3D12MA_ASSERT(!upperAddress && "ALLOCATION_FLAG_UPPER_ADDRESS can be used only with linear algorithm.");
- D3D12MA_ASSERT(pAllocationRequest != NULL);
- D3D12MA_HEAVY_ASSERT(Validate());
- // There is not enough total free space in this block to fullfill the request: Early return.
- if (m_SumFreeSize < allocSize + GetDebugMargin())
- {
- return false;
- }
- // New algorithm, efficiently searching freeSuballocationsBySize.
- const size_t freeSuballocCount = m_FreeSuballocationsBySize.size();
- if (freeSuballocCount > 0)
- {
- // Find first free suballocation with size not less than allocSize + GetDebugMargin().
- SuballocationList::iterator* const it = BinaryFindFirstNotLess(
- m_FreeSuballocationsBySize.data(),
- m_FreeSuballocationsBySize.data() + freeSuballocCount,
- allocSize + GetDebugMargin(),
- SuballocationItemSizeLess());
- size_t index = it - m_FreeSuballocationsBySize.data();
- for (; index < freeSuballocCount; ++index)
- {
- if (CheckAllocation(
- allocSize,
- allocAlignment,
- m_FreeSuballocationsBySize[index],
- &pAllocationRequest->allocHandle,
- &pAllocationRequest->sumFreeSize,
- &pAllocationRequest->sumItemSize,
- &pAllocationRequest->zeroInitialized))
- {
- pAllocationRequest->item = m_FreeSuballocationsBySize[index];
- return true;
- }
- }
- }
- return false;
- }
- void BlockMetadata_Generic::Alloc(
- const AllocationRequest& request,
- UINT64 allocSize,
- void* privateData)
- {
- D3D12MA_ASSERT(request.item != m_Suballocations.end());
- Suballocation& suballoc = *request.item;
- // Given suballocation is a free block.
- D3D12MA_ASSERT(suballoc.type == SUBALLOCATION_TYPE_FREE);
- // Given offset is inside this suballocation.
- UINT64 offset = (UINT64)request.allocHandle - 1;
- D3D12MA_ASSERT(offset >= suballoc.offset);
- const UINT64 paddingBegin = offset - suballoc.offset;
- D3D12MA_ASSERT(suballoc.size >= paddingBegin + allocSize);
- const UINT64 paddingEnd = suballoc.size - paddingBegin - allocSize;
- // Unregister this free suballocation from m_FreeSuballocationsBySize and update
- // it to become used.
- UnregisterFreeSuballocation(request.item);
- suballoc.offset = offset;
- suballoc.size = allocSize;
- suballoc.type = SUBALLOCATION_TYPE_ALLOCATION;
- suballoc.privateData = privateData;
- // If there are any free bytes remaining at the end, insert new free suballocation after current one.
- if (paddingEnd)
- {
- Suballocation paddingSuballoc = {};
- paddingSuballoc.offset = offset + allocSize;
- paddingSuballoc.size = paddingEnd;
- paddingSuballoc.type = SUBALLOCATION_TYPE_FREE;
- SuballocationList::iterator next = request.item;
- ++next;
- const SuballocationList::iterator paddingEndItem =
- m_Suballocations.insert(next, paddingSuballoc);
- RegisterFreeSuballocation(paddingEndItem);
- }
- // If there are any free bytes remaining at the beginning, insert new free suballocation before current one.
- if (paddingBegin)
- {
- Suballocation paddingSuballoc = {};
- paddingSuballoc.offset = offset - paddingBegin;
- paddingSuballoc.size = paddingBegin;
- paddingSuballoc.type = SUBALLOCATION_TYPE_FREE;
- const SuballocationList::iterator paddingBeginItem =
- m_Suballocations.insert(request.item, paddingSuballoc);
- RegisterFreeSuballocation(paddingBeginItem);
- }
- // Update totals.
- m_FreeCount = m_FreeCount - 1;
- if (paddingBegin > 0)
- {
- ++m_FreeCount;
- }
- if (paddingEnd > 0)
- {
- ++m_FreeCount;
- }
- m_SumFreeSize -= allocSize;
- m_ZeroInitializedRange.MarkRangeAsUsed(offset, offset + allocSize);
- }
- void BlockMetadata_Generic::Free(AllocHandle allocHandle)
- {
- FreeSuballocation(FindAtOffset((UINT64)allocHandle - 1).dropConst());
- }
- void BlockMetadata_Generic::Clear()
- {
- m_FreeCount = 1;
- m_SumFreeSize = GetSize();
- m_Suballocations.clear();
- Suballocation suballoc = {};
- suballoc.offset = 0;
- suballoc.size = GetSize();
- suballoc.type = SUBALLOCATION_TYPE_FREE;
- m_Suballocations.push_back(suballoc);
- m_FreeSuballocationsBySize.clear();
- m_FreeSuballocationsBySize.push_back(m_Suballocations.begin());
- }
- SuballocationList::const_iterator BlockMetadata_Generic::FindAtOffset(UINT64 offset) const
- {
- const UINT64 last = m_Suballocations.crbegin()->offset;
- if (last == offset)
- return m_Suballocations.crbegin();
- const UINT64 first = m_Suballocations.cbegin()->offset;
- if (first == offset)
- return m_Suballocations.cbegin();
- const size_t suballocCount = m_Suballocations.size();
- const UINT64 step = (last - first + m_Suballocations.cbegin()->size) / suballocCount;
- auto findSuballocation = [&](auto begin, auto end) -> SuballocationList::const_iterator
- {
- for (auto suballocItem = begin;
- suballocItem != end;
- ++suballocItem)
- {
- const Suballocation& suballoc = *suballocItem;
- if (suballoc.offset == offset)
- return suballocItem;
- }
- D3D12MA_ASSERT(false && "Not found!");
- return m_Suballocations.end();
- };
- // If requested offset is closer to the end of range, search from the end
- if ((offset - first) > suballocCount * step / 2)
- {
- return findSuballocation(m_Suballocations.crbegin(), m_Suballocations.crend());
- }
- return findSuballocation(m_Suballocations.cbegin(), m_Suballocations.cend());
- }
- bool BlockMetadata_Generic::ValidateFreeSuballocationList() const
- {
- UINT64 lastSize = 0;
- for (size_t i = 0, count = m_FreeSuballocationsBySize.size(); i < count; ++i)
- {
- const SuballocationList::iterator it = m_FreeSuballocationsBySize[i];
- D3D12MA_VALIDATE(it->type == SUBALLOCATION_TYPE_FREE);
- D3D12MA_VALIDATE(it->size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER);
- D3D12MA_VALIDATE(it->size >= lastSize);
- lastSize = it->size;
- }
- return true;
- }
- bool BlockMetadata_Generic::CheckAllocation(
- UINT64 allocSize,
- UINT64 allocAlignment,
- SuballocationList::const_iterator suballocItem,
- AllocHandle* pAllocHandle,
- UINT64* pSumFreeSize,
- UINT64* pSumItemSize,
- BOOL* pZeroInitialized) const
- {
- D3D12MA_ASSERT(allocSize > 0);
- D3D12MA_ASSERT(suballocItem != m_Suballocations.cend());
- D3D12MA_ASSERT(pAllocHandle != NULL && pZeroInitialized != NULL);
- *pSumFreeSize = 0;
- *pSumItemSize = 0;
- *pZeroInitialized = FALSE;
- const Suballocation& suballoc = *suballocItem;
- D3D12MA_ASSERT(suballoc.type == SUBALLOCATION_TYPE_FREE);
- *pSumFreeSize = suballoc.size;
- // Size of this suballocation is too small for this request: Early return.
- if (suballoc.size < allocSize)
- {
- return false;
- }
- // Start from offset equal to beginning of this suballocation and debug margin of previous allocation if present.
- UINT64 offset = suballoc.offset + (suballocItem == m_Suballocations.cbegin() ? 0 : GetDebugMargin());
- // Apply alignment.
- offset = AlignUp(offset, allocAlignment);
- // Calculate padding at the beginning based on current offset.
- const UINT64 paddingBegin = offset - suballoc.offset;
- // Fail if requested size plus margin after is bigger than size of this suballocation.
- if (paddingBegin + allocSize + GetDebugMargin() > suballoc.size)
- {
- return false;
- }
- // All tests passed: Success. Offset is already filled.
- *pZeroInitialized = m_ZeroInitializedRange.IsRangeZeroInitialized(offset, offset + allocSize);
- *pAllocHandle = (AllocHandle)(offset + 1);
- return true;
- }
- void BlockMetadata_Generic::MergeFreeWithNext(SuballocationList::iterator item)
- {
- D3D12MA_ASSERT(item != m_Suballocations.end());
- D3D12MA_ASSERT(item->type == SUBALLOCATION_TYPE_FREE);
- SuballocationList::iterator nextItem = item;
- ++nextItem;
- D3D12MA_ASSERT(nextItem != m_Suballocations.end());
- D3D12MA_ASSERT(nextItem->type == SUBALLOCATION_TYPE_FREE);
- item->size += nextItem->size;
- --m_FreeCount;
- m_Suballocations.erase(nextItem);
- }
- SuballocationList::iterator BlockMetadata_Generic::FreeSuballocation(SuballocationList::iterator suballocItem)
- {
- // Change this suballocation to be marked as free.
- Suballocation& suballoc = *suballocItem;
- suballoc.type = SUBALLOCATION_TYPE_FREE;
- suballoc.privateData = NULL;
- // Update totals.
- ++m_FreeCount;
- m_SumFreeSize += suballoc.size;
- // Merge with previous and/or next suballocation if it's also free.
- bool mergeWithNext = false;
- bool mergeWithPrev = false;
- SuballocationList::iterator nextItem = suballocItem;
- ++nextItem;
- if ((nextItem != m_Suballocations.end()) && (nextItem->type == SUBALLOCATION_TYPE_FREE))
- {
- mergeWithNext = true;
- }
- SuballocationList::iterator prevItem = suballocItem;
- if (suballocItem != m_Suballocations.begin())
- {
- --prevItem;
- if (prevItem->type == SUBALLOCATION_TYPE_FREE)
- {
- mergeWithPrev = true;
- }
- }
- if (mergeWithNext)
- {
- UnregisterFreeSuballocation(nextItem);
- MergeFreeWithNext(suballocItem);
- }
- if (mergeWithPrev)
- {
- UnregisterFreeSuballocation(prevItem);
- MergeFreeWithNext(prevItem);
- RegisterFreeSuballocation(prevItem);
- return prevItem;
- }
- else
- {
- RegisterFreeSuballocation(suballocItem);
- return suballocItem;
- }
- }
- void BlockMetadata_Generic::RegisterFreeSuballocation(SuballocationList::iterator item)
- {
- D3D12MA_ASSERT(item->type == SUBALLOCATION_TYPE_FREE);
- D3D12MA_ASSERT(item->size > 0);
- // You may want to enable this validation at the beginning or at the end of
- // this function, depending on what do you want to check.
- D3D12MA_HEAVY_ASSERT(ValidateFreeSuballocationList());
- if (item->size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
- {
- if (m_FreeSuballocationsBySize.empty())
- {
- m_FreeSuballocationsBySize.push_back(item);
- }
- else
- {
- m_FreeSuballocationsBySize.InsertSorted(item, SuballocationItemSizeLess());
- }
- }
- //D3D12MA_HEAVY_ASSERT(ValidateFreeSuballocationList());
- }
- void BlockMetadata_Generic::UnregisterFreeSuballocation(SuballocationList::iterator item)
- {
- D3D12MA_ASSERT(item->type == SUBALLOCATION_TYPE_FREE);
- D3D12MA_ASSERT(item->size > 0);
- // You may want to enable this validation at the beginning or at the end of
- // this function, depending on what do you want to check.
- D3D12MA_HEAVY_ASSERT(ValidateFreeSuballocationList());
- if (item->size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
- {
- SuballocationList::iterator* const it = BinaryFindFirstNotLess(
- m_FreeSuballocationsBySize.data(),
- m_FreeSuballocationsBySize.data() + m_FreeSuballocationsBySize.size(),
- item,
- SuballocationItemSizeLess());
- for (size_t index = it - m_FreeSuballocationsBySize.data();
- index < m_FreeSuballocationsBySize.size();
- ++index)
- {
- if (m_FreeSuballocationsBySize[index] == item)
- {
- m_FreeSuballocationsBySize.remove(index);
- return;
- }
- D3D12MA_ASSERT((m_FreeSuballocationsBySize[index]->size == item->size) && "Not found.");
- }
- D3D12MA_ASSERT(0 && "Not found.");
- }
- //D3D12MA_HEAVY_ASSERT(ValidateFreeSuballocationList());
- }
- void BlockMetadata_Generic::SetAllocationPrivateData(AllocHandle allocHandle, void* privateData)
- {
- Suballocation& suballoc = *FindAtOffset((UINT64)allocHandle - 1).dropConst();
- suballoc.privateData = privateData;
- }
- void BlockMetadata_Generic::AddStatistics(Statistics& inoutStats) const
- {
- inoutStats.BlockCount++;
- inoutStats.AllocationCount += (UINT)m_Suballocations.size() - m_FreeCount;
- inoutStats.BlockBytes += GetSize();
- inoutStats.AllocationBytes += GetSize() - m_SumFreeSize;
- }
- void BlockMetadata_Generic::AddDetailedStatistics(DetailedStatistics& inoutStats) const
- {
- inoutStats.Stats.BlockCount++;
- inoutStats.Stats.BlockBytes += GetSize();
- for (const auto& suballoc : m_Suballocations)
- {
- if (suballoc.type == SUBALLOCATION_TYPE_FREE)
- AddDetailedStatisticsUnusedRange(inoutStats, suballoc.size);
- else
- AddDetailedStatisticsAllocation(inoutStats, suballoc.size);
- }
- }
- void BlockMetadata_Generic::WriteAllocationInfoToJson(JsonWriter& json) const
- {
- PrintDetailedMap_Begin(json, GetSumFreeSize(), GetAllocationCount(), m_FreeCount);
- for (const auto& suballoc : m_Suballocations)
- {
- if (suballoc.type == SUBALLOCATION_TYPE_FREE)
- PrintDetailedMap_UnusedRange(json, suballoc.offset, suballoc.size);
- else
- PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.privateData);
- }
- PrintDetailedMap_End(json);
- }
- #endif // _D3D12MA_BLOCK_METADATA_GENERIC_FUNCTIONS
- #endif // _D3D12MA_BLOCK_METADATA_GENERIC
- #endif // #if 0
- #ifndef _D3D12MA_BLOCK_METADATA_LINEAR
- class BlockMetadata_Linear : public BlockMetadata
- {
- public:
- BlockMetadata_Linear(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual);
- virtual ~BlockMetadata_Linear() = default;
- UINT64 GetSumFreeSize() const override { return m_SumFreeSize; }
- bool IsEmpty() const override { return GetAllocationCount() == 0; }
- UINT64 GetAllocationOffset(AllocHandle allocHandle) const override { return (UINT64)allocHandle - 1; };
- void Init(UINT64 size) override;
- bool Validate() const override;
- size_t GetAllocationCount() const override;
- size_t GetFreeRegionsCount() const override;
- void GetAllocationInfo(AllocHandle allocHandle, VIRTUAL_ALLOCATION_INFO& outInfo) const override;
- bool CreateAllocationRequest(
- UINT64 allocSize,
- UINT64 allocAlignment,
- bool upperAddress,
- UINT32 strategy,
- AllocationRequest* pAllocationRequest) override;
- void Alloc(
- const AllocationRequest& request,
- UINT64 allocSize,
- void* privateData) override;
- void Free(AllocHandle allocHandle) override;
- void Clear() override;
- AllocHandle GetAllocationListBegin() const override;
- AllocHandle GetNextAllocation(AllocHandle prevAlloc) const override;
- UINT64 GetNextFreeRegionSize(AllocHandle alloc) const override;
- void* GetAllocationPrivateData(AllocHandle allocHandle) const override;
- void SetAllocationPrivateData(AllocHandle allocHandle, void* privateData) override;
- void AddStatistics(Statistics& inoutStats) const override;
- void AddDetailedStatistics(DetailedStatistics& inoutStats) const override;
- void WriteAllocationInfoToJson(JsonWriter& json) const override;
- void DebugLogAllAllocations() const override;
- private:
- /*
- There are two suballocation vectors, used in ping-pong way.
- The one with index m_1stVectorIndex is called 1st.
- The one with index (m_1stVectorIndex ^ 1) is called 2nd.
- 2nd can be non-empty only when 1st is not empty.
- When 2nd is not empty, m_2ndVectorMode indicates its mode of operation.
- */
- typedef Vector<Suballocation> SuballocationVectorType;
- enum ALLOC_REQUEST_TYPE
- {
- ALLOC_REQUEST_UPPER_ADDRESS,
- ALLOC_REQUEST_END_OF_1ST,
- ALLOC_REQUEST_END_OF_2ND,
- };
- enum SECOND_VECTOR_MODE
- {
- SECOND_VECTOR_EMPTY,
- /*
- Suballocations in 2nd vector are created later than the ones in 1st, but they
- all have smaller offset.
- */
- SECOND_VECTOR_RING_BUFFER,
- /*
- Suballocations in 2nd vector are upper side of double stack.
- They all have offsets higher than those in 1st vector.
- Top of this stack means smaller offsets, but higher indices in this vector.
- */
- SECOND_VECTOR_DOUBLE_STACK,
- };
- UINT64 m_SumFreeSize;
- SuballocationVectorType m_Suballocations0, m_Suballocations1;
- UINT32 m_1stVectorIndex;
- SECOND_VECTOR_MODE m_2ndVectorMode;
- // Number of items in 1st vector with hAllocation = null at the beginning.
- size_t m_1stNullItemsBeginCount;
- // Number of other items in 1st vector with hAllocation = null somewhere in the middle.
- size_t m_1stNullItemsMiddleCount;
- // Number of items in 2nd vector with hAllocation = null.
- size_t m_2ndNullItemsCount;
- SuballocationVectorType& AccessSuballocations1st() { return m_1stVectorIndex ? m_Suballocations1 : m_Suballocations0; }
- SuballocationVectorType& AccessSuballocations2nd() { return m_1stVectorIndex ? m_Suballocations0 : m_Suballocations1; }
- const SuballocationVectorType& AccessSuballocations1st() const { return m_1stVectorIndex ? m_Suballocations1 : m_Suballocations0; }
- const SuballocationVectorType& AccessSuballocations2nd() const { return m_1stVectorIndex ? m_Suballocations0 : m_Suballocations1; }
- Suballocation& FindSuballocation(UINT64 offset) const;
- bool ShouldCompact1st() const;
- void CleanupAfterFree();
- bool CreateAllocationRequest_LowerAddress(
- UINT64 allocSize,
- UINT64 allocAlignment,
- AllocationRequest* pAllocationRequest);
- bool CreateAllocationRequest_UpperAddress(
- UINT64 allocSize,
- UINT64 allocAlignment,
- AllocationRequest* pAllocationRequest);
- D3D12MA_CLASS_NO_COPY(BlockMetadata_Linear)
- };
- #ifndef _D3D12MA_BLOCK_METADATA_LINEAR_FUNCTIONS
- BlockMetadata_Linear::BlockMetadata_Linear(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual)
- : BlockMetadata(allocationCallbacks, isVirtual),
- m_SumFreeSize(0),
- m_Suballocations0(*allocationCallbacks),
- m_Suballocations1(*allocationCallbacks),
- m_1stVectorIndex(0),
- m_2ndVectorMode(SECOND_VECTOR_EMPTY),
- m_1stNullItemsBeginCount(0),
- m_1stNullItemsMiddleCount(0),
- m_2ndNullItemsCount(0)
- {
- D3D12MA_ASSERT(allocationCallbacks);
- }
- void BlockMetadata_Linear::Init(UINT64 size)
- {
- BlockMetadata::Init(size);
- m_SumFreeSize = size;
- }
- bool BlockMetadata_Linear::Validate() const
- {
- D3D12MA_VALIDATE(GetSumFreeSize() <= GetSize());
- const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
- const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
- D3D12MA_VALIDATE(suballocations2nd.empty() == (m_2ndVectorMode == SECOND_VECTOR_EMPTY));
- D3D12MA_VALIDATE(!suballocations1st.empty() ||
- suballocations2nd.empty() ||
- m_2ndVectorMode != SECOND_VECTOR_RING_BUFFER);
- if (!suballocations1st.empty())
- {
- // Null item at the beginning should be accounted into m_1stNullItemsBeginCount.
- D3D12MA_VALIDATE(suballocations1st[m_1stNullItemsBeginCount].type != SUBALLOCATION_TYPE_FREE);
- // Null item at the end should be just pop_back().
- D3D12MA_VALIDATE(suballocations1st.back().type != SUBALLOCATION_TYPE_FREE);
- }
- if (!suballocations2nd.empty())
- {
- // Null item at the end should be just pop_back().
- D3D12MA_VALIDATE(suballocations2nd.back().type != SUBALLOCATION_TYPE_FREE);
- }
- D3D12MA_VALIDATE(m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount <= suballocations1st.size());
- D3D12MA_VALIDATE(m_2ndNullItemsCount <= suballocations2nd.size());
- UINT64 sumUsedSize = 0;
- const size_t suballoc1stCount = suballocations1st.size();
- UINT64 offset = 0;
- if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
- {
- const size_t suballoc2ndCount = suballocations2nd.size();
- size_t nullItem2ndCount = 0;
- for (size_t i = 0; i < suballoc2ndCount; ++i)
- {
- const Suballocation& suballoc = suballocations2nd[i];
- const bool currFree = (suballoc.type == SUBALLOCATION_TYPE_FREE);
- const Allocation* alloc = (Allocation*)suballoc.privateData;
- if (!IsVirtual())
- {
- D3D12MA_VALIDATE(currFree == (alloc == NULL));
- }
- D3D12MA_VALIDATE(suballoc.offset >= offset);
- if (!currFree)
- {
- if (!IsVirtual())
- {
- D3D12MA_VALIDATE(GetAllocationOffset(alloc->GetAllocHandle()) == suballoc.offset);
- D3D12MA_VALIDATE(alloc->GetSize() == suballoc.size);
- }
- sumUsedSize += suballoc.size;
- }
- else
- {
- ++nullItem2ndCount;
- }
- offset = suballoc.offset + suballoc.size + GetDebugMargin();
- }
- D3D12MA_VALIDATE(nullItem2ndCount == m_2ndNullItemsCount);
- }
- for (size_t i = 0; i < m_1stNullItemsBeginCount; ++i)
- {
- const Suballocation& suballoc = suballocations1st[i];
- D3D12MA_VALIDATE(suballoc.type == SUBALLOCATION_TYPE_FREE &&
- suballoc.privateData == NULL);
- }
- size_t nullItem1stCount = m_1stNullItemsBeginCount;
- for (size_t i = m_1stNullItemsBeginCount; i < suballoc1stCount; ++i)
- {
- const Suballocation& suballoc = suballocations1st[i];
- const bool currFree = (suballoc.type == SUBALLOCATION_TYPE_FREE);
- const Allocation* alloc = (Allocation*)suballoc.privateData;
- if (!IsVirtual())
- {
- D3D12MA_VALIDATE(currFree == (alloc == NULL));
- }
- D3D12MA_VALIDATE(suballoc.offset >= offset);
- D3D12MA_VALIDATE(i >= m_1stNullItemsBeginCount || currFree);
- if (!currFree)
- {
- if (!IsVirtual())
- {
- D3D12MA_VALIDATE(GetAllocationOffset(alloc->GetAllocHandle()) == suballoc.offset);
- D3D12MA_VALIDATE(alloc->GetSize() == suballoc.size);
- }
- sumUsedSize += suballoc.size;
- }
- else
- {
- ++nullItem1stCount;
- }
- offset = suballoc.offset + suballoc.size + GetDebugMargin();
- }
- D3D12MA_VALIDATE(nullItem1stCount == m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount);
- if (m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
- {
- const size_t suballoc2ndCount = suballocations2nd.size();
- size_t nullItem2ndCount = 0;
- for (size_t i = suballoc2ndCount; i--; )
- {
- const Suballocation& suballoc = suballocations2nd[i];
- const bool currFree = (suballoc.type == SUBALLOCATION_TYPE_FREE);
- const Allocation* alloc = (Allocation*)suballoc.privateData;
- if (!IsVirtual())
- {
- D3D12MA_VALIDATE(currFree == (alloc == NULL));
- }
- D3D12MA_VALIDATE(suballoc.offset >= offset);
- if (!currFree)
- {
- if (!IsVirtual())
- {
- D3D12MA_VALIDATE(GetAllocationOffset(alloc->GetAllocHandle()) == suballoc.offset);
- D3D12MA_VALIDATE(alloc->GetSize() == suballoc.size);
- }
- sumUsedSize += suballoc.size;
- }
- else
- {
- ++nullItem2ndCount;
- }
- offset = suballoc.offset + suballoc.size + GetDebugMargin();
- }
- D3D12MA_VALIDATE(nullItem2ndCount == m_2ndNullItemsCount);
- }
- D3D12MA_VALIDATE(offset <= GetSize());
- D3D12MA_VALIDATE(m_SumFreeSize == GetSize() - sumUsedSize);
- return true;
- }
- size_t BlockMetadata_Linear::GetAllocationCount() const
- {
- return AccessSuballocations1st().size() - m_1stNullItemsBeginCount - m_1stNullItemsMiddleCount +
- AccessSuballocations2nd().size() - m_2ndNullItemsCount;
- }
- size_t BlockMetadata_Linear::GetFreeRegionsCount() const
- {
- // Function only used for defragmentation, which is disabled for this algorithm
- D3D12MA_ASSERT(0);
- return SIZE_MAX;
- }
- void BlockMetadata_Linear::GetAllocationInfo(AllocHandle allocHandle, VIRTUAL_ALLOCATION_INFO& outInfo) const
- {
- const Suballocation& suballoc = FindSuballocation((UINT64)allocHandle - 1);
- outInfo.Offset = suballoc.offset;
- outInfo.Size = suballoc.size;
- outInfo.pPrivateData = suballoc.privateData;
- }
- bool BlockMetadata_Linear::CreateAllocationRequest(
- UINT64 allocSize,
- UINT64 allocAlignment,
- bool upperAddress,
- UINT32 strategy,
- AllocationRequest* pAllocationRequest)
- {
- D3D12MA_ASSERT(allocSize > 0 && "Cannot allocate empty block!");
- D3D12MA_ASSERT(pAllocationRequest != NULL);
- D3D12MA_HEAVY_ASSERT(Validate());
- pAllocationRequest->size = allocSize;
- return upperAddress ?
- CreateAllocationRequest_UpperAddress(
- allocSize, allocAlignment, pAllocationRequest) :
- CreateAllocationRequest_LowerAddress(
- allocSize, allocAlignment, pAllocationRequest);
- }
- void BlockMetadata_Linear::Alloc(
- const AllocationRequest& request,
- UINT64 allocSize,
- void* privateData)
- {
- UINT64 offset = (UINT64)request.allocHandle - 1;
- const Suballocation newSuballoc = { offset, request.size, privateData, SUBALLOCATION_TYPE_ALLOCATION };
- switch (request.algorithmData)
- {
- case ALLOC_REQUEST_UPPER_ADDRESS:
- {
- D3D12MA_ASSERT(m_2ndVectorMode != SECOND_VECTOR_RING_BUFFER &&
- "CRITICAL ERROR: Trying to use linear allocator as double stack while it was already used as ring buffer.");
- SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
- suballocations2nd.push_back(newSuballoc);
- m_2ndVectorMode = SECOND_VECTOR_DOUBLE_STACK;
- break;
- }
- case ALLOC_REQUEST_END_OF_1ST:
- {
- SuballocationVectorType& suballocations1st = AccessSuballocations1st();
- D3D12MA_ASSERT(suballocations1st.empty() ||
- offset >= suballocations1st.back().offset + suballocations1st.back().size);
- // Check if it fits before the end of the block.
- D3D12MA_ASSERT(offset + request.size <= GetSize());
- suballocations1st.push_back(newSuballoc);
- break;
- }
- case ALLOC_REQUEST_END_OF_2ND:
- {
- SuballocationVectorType& suballocations1st = AccessSuballocations1st();
- // New allocation at the end of 2-part ring buffer, so before first allocation from 1st vector.
- D3D12MA_ASSERT(!suballocations1st.empty() &&
- offset + request.size <= suballocations1st[m_1stNullItemsBeginCount].offset);
- SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
- switch (m_2ndVectorMode)
- {
- case SECOND_VECTOR_EMPTY:
- // First allocation from second part ring buffer.
- D3D12MA_ASSERT(suballocations2nd.empty());
- m_2ndVectorMode = SECOND_VECTOR_RING_BUFFER;
- break;
- case SECOND_VECTOR_RING_BUFFER:
- // 2-part ring buffer is already started.
- D3D12MA_ASSERT(!suballocations2nd.empty());
- break;
- case SECOND_VECTOR_DOUBLE_STACK:
- D3D12MA_ASSERT(0 && "CRITICAL ERROR: Trying to use linear allocator as ring buffer while it was already used as double stack.");
- break;
- default:
- D3D12MA_ASSERT(0);
- }
- suballocations2nd.push_back(newSuballoc);
- break;
- }
- default:
- D3D12MA_ASSERT(0 && "CRITICAL INTERNAL ERROR.");
- }
- m_SumFreeSize -= newSuballoc.size;
- }
- void BlockMetadata_Linear::Free(AllocHandle allocHandle)
- {
- SuballocationVectorType& suballocations1st = AccessSuballocations1st();
- SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
- UINT64 offset = (UINT64)allocHandle - 1;
- if (!suballocations1st.empty())
- {
- // First allocation: Mark it as next empty at the beginning.
- Suballocation& firstSuballoc = suballocations1st[m_1stNullItemsBeginCount];
- if (firstSuballoc.offset == offset)
- {
- firstSuballoc.type = SUBALLOCATION_TYPE_FREE;
- firstSuballoc.privateData = NULL;
- m_SumFreeSize += firstSuballoc.size;
- ++m_1stNullItemsBeginCount;
- CleanupAfterFree();
- return;
- }
- }
- // Last allocation in 2-part ring buffer or top of upper stack (same logic).
- if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER ||
- m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
- {
- Suballocation& lastSuballoc = suballocations2nd.back();
- if (lastSuballoc.offset == offset)
- {
- m_SumFreeSize += lastSuballoc.size;
- suballocations2nd.pop_back();
- CleanupAfterFree();
- return;
- }
- }
- // Last allocation in 1st vector.
- else if (m_2ndVectorMode == SECOND_VECTOR_EMPTY)
- {
- Suballocation& lastSuballoc = suballocations1st.back();
- if (lastSuballoc.offset == offset)
- {
- m_SumFreeSize += lastSuballoc.size;
- suballocations1st.pop_back();
- CleanupAfterFree();
- return;
- }
- }
- Suballocation refSuballoc;
- refSuballoc.offset = offset;
- // Rest of members stays uninitialized intentionally for better performance.
- // Item from the middle of 1st vector.
- {
- const SuballocationVectorType::iterator it = BinaryFindSorted(
- suballocations1st.begin() + m_1stNullItemsBeginCount,
- suballocations1st.end(),
- refSuballoc,
- SuballocationOffsetLess());
- if (it != suballocations1st.end())
- {
- it->type = SUBALLOCATION_TYPE_FREE;
- it->privateData = NULL;
- ++m_1stNullItemsMiddleCount;
- m_SumFreeSize += it->size;
- CleanupAfterFree();
- return;
- }
- }
- if (m_2ndVectorMode != SECOND_VECTOR_EMPTY)
- {
- // Item from the middle of 2nd vector.
- const SuballocationVectorType::iterator it = m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER ?
- BinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, SuballocationOffsetLess()) :
- BinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, SuballocationOffsetGreater());
- if (it != suballocations2nd.end())
- {
- it->type = SUBALLOCATION_TYPE_FREE;
- it->privateData = NULL;
- ++m_2ndNullItemsCount;
- m_SumFreeSize += it->size;
- CleanupAfterFree();
- return;
- }
- }
- D3D12MA_ASSERT(0 && "Allocation to free not found in linear allocator!");
- }
- void BlockMetadata_Linear::Clear()
- {
- m_SumFreeSize = GetSize();
- m_Suballocations0.clear();
- m_Suballocations1.clear();
- // Leaving m_1stVectorIndex unchanged - it doesn't matter.
- m_2ndVectorMode = SECOND_VECTOR_EMPTY;
- m_1stNullItemsBeginCount = 0;
- m_1stNullItemsMiddleCount = 0;
- m_2ndNullItemsCount = 0;
- }
- AllocHandle BlockMetadata_Linear::GetAllocationListBegin() const
- {
- // Function only used for defragmentation, which is disabled for this algorithm
- D3D12MA_ASSERT(0);
- return (AllocHandle)0;
- }
- AllocHandle BlockMetadata_Linear::GetNextAllocation(AllocHandle prevAlloc) const
- {
- // Function only used for defragmentation, which is disabled for this algorithm
- D3D12MA_ASSERT(0);
- return (AllocHandle)0;
- }
- UINT64 BlockMetadata_Linear::GetNextFreeRegionSize(AllocHandle alloc) const
- {
- // Function only used for defragmentation, which is disabled for this algorithm
- D3D12MA_ASSERT(0);
- return 0;
- }
- void* BlockMetadata_Linear::GetAllocationPrivateData(AllocHandle allocHandle) const
- {
- return FindSuballocation((UINT64)allocHandle - 1).privateData;
- }
- void BlockMetadata_Linear::SetAllocationPrivateData(AllocHandle allocHandle, void* privateData)
- {
- Suballocation& suballoc = FindSuballocation((UINT64)allocHandle - 1);
- suballoc.privateData = privateData;
- }
- void BlockMetadata_Linear::AddStatistics(Statistics& inoutStats) const
- {
- inoutStats.BlockCount++;
- inoutStats.AllocationCount += (UINT)GetAllocationCount();
- inoutStats.BlockBytes += GetSize();
- inoutStats.AllocationBytes += GetSize() - m_SumFreeSize;
- }
- void BlockMetadata_Linear::AddDetailedStatistics(DetailedStatistics& inoutStats) const
- {
- inoutStats.Stats.BlockCount++;
- inoutStats.Stats.BlockBytes += GetSize();
- const UINT64 size = GetSize();
- const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
- const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
- const size_t suballoc1stCount = suballocations1st.size();
- const size_t suballoc2ndCount = suballocations2nd.size();
- UINT64 lastOffset = 0;
- if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
- {
- const UINT64 freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
- size_t nextAlloc2ndIndex = 0;
- while (lastOffset < freeSpace2ndTo1stEnd)
- {
- // Find next non-null allocation or move nextAllocIndex to the end.
- while (nextAlloc2ndIndex < suballoc2ndCount &&
- suballocations2nd[nextAlloc2ndIndex].privateData == NULL)
- {
- ++nextAlloc2ndIndex;
- }
- // Found non-null allocation.
- if (nextAlloc2ndIndex < suballoc2ndCount)
- {
- const Suballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
- // 1. Process free space before this allocation.
- if (lastOffset < suballoc.offset)
- {
- // There is free space from lastOffset to suballoc.offset.
- const UINT64 unusedRangeSize = suballoc.offset - lastOffset;
- AddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize);
- }
- // 2. Process this allocation.
- // There is allocation with suballoc.offset, suballoc.size.
- AddDetailedStatisticsAllocation(inoutStats, suballoc.size);
- // 3. Prepare for next iteration.
- lastOffset = suballoc.offset + suballoc.size;
- ++nextAlloc2ndIndex;
- }
- // We are at the end.
- else
- {
- // There is free space from lastOffset to freeSpace2ndTo1stEnd.
- if (lastOffset < freeSpace2ndTo1stEnd)
- {
- const UINT64 unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset;
- AddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize);
- }
- // End of loop.
- lastOffset = freeSpace2ndTo1stEnd;
- }
- }
- }
- size_t nextAlloc1stIndex = m_1stNullItemsBeginCount;
- const UINT64 freeSpace1stTo2ndEnd =
- m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size;
- while (lastOffset < freeSpace1stTo2ndEnd)
- {
- // Find next non-null allocation or move nextAllocIndex to the end.
- while (nextAlloc1stIndex < suballoc1stCount &&
- suballocations1st[nextAlloc1stIndex].privateData == NULL)
- {
- ++nextAlloc1stIndex;
- }
- // Found non-null allocation.
- if (nextAlloc1stIndex < suballoc1stCount)
- {
- const Suballocation& suballoc = suballocations1st[nextAlloc1stIndex];
- // 1. Process free space before this allocation.
- if (lastOffset < suballoc.offset)
- {
- // There is free space from lastOffset to suballoc.offset.
- const UINT64 unusedRangeSize = suballoc.offset - lastOffset;
- AddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize);
- }
- // 2. Process this allocation.
- // There is allocation with suballoc.offset, suballoc.size.
- AddDetailedStatisticsAllocation(inoutStats, suballoc.size);
- // 3. Prepare for next iteration.
- lastOffset = suballoc.offset + suballoc.size;
- ++nextAlloc1stIndex;
- }
- // We are at the end.
- else
- {
- // There is free space from lastOffset to freeSpace1stTo2ndEnd.
- if (lastOffset < freeSpace1stTo2ndEnd)
- {
- const UINT64 unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset;
- AddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize);
- }
- // End of loop.
- lastOffset = freeSpace1stTo2ndEnd;
- }
- }
- if (m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
- {
- size_t nextAlloc2ndIndex = suballocations2nd.size() - 1;
- while (lastOffset < size)
- {
- // Find next non-null allocation or move nextAllocIndex to the end.
- while (nextAlloc2ndIndex != SIZE_MAX &&
- suballocations2nd[nextAlloc2ndIndex].privateData == NULL)
- {
- --nextAlloc2ndIndex;
- }
- // Found non-null allocation.
- if (nextAlloc2ndIndex != SIZE_MAX)
- {
- const Suballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
- // 1. Process free space before this allocation.
- if (lastOffset < suballoc.offset)
- {
- // There is free space from lastOffset to suballoc.offset.
- const UINT64 unusedRangeSize = suballoc.offset - lastOffset;
- AddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize);
- }
- // 2. Process this allocation.
- // There is allocation with suballoc.offset, suballoc.size.
- AddDetailedStatisticsAllocation(inoutStats, suballoc.size);
- // 3. Prepare for next iteration.
- lastOffset = suballoc.offset + suballoc.size;
- --nextAlloc2ndIndex;
- }
- // We are at the end.
- else
- {
- // There is free space from lastOffset to size.
- if (lastOffset < size)
- {
- const UINT64 unusedRangeSize = size - lastOffset;
- AddDetailedStatisticsUnusedRange(inoutStats, unusedRangeSize);
- }
- // End of loop.
- lastOffset = size;
- }
- }
- }
- }
- void BlockMetadata_Linear::WriteAllocationInfoToJson(JsonWriter& json) const
- {
- const UINT64 size = GetSize();
- const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
- const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
- const size_t suballoc1stCount = suballocations1st.size();
- const size_t suballoc2ndCount = suballocations2nd.size();
- // FIRST PASS
- size_t unusedRangeCount = 0;
- UINT64 usedBytes = 0;
- UINT64 lastOffset = 0;
- size_t alloc2ndCount = 0;
- if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
- {
- const UINT64 freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
- size_t nextAlloc2ndIndex = 0;
- while (lastOffset < freeSpace2ndTo1stEnd)
- {
- // Find next non-null allocation or move nextAlloc2ndIndex to the end.
- while (nextAlloc2ndIndex < suballoc2ndCount &&
- suballocations2nd[nextAlloc2ndIndex].privateData == NULL)
- {
- ++nextAlloc2ndIndex;
- }
- // Found non-null allocation.
- if (nextAlloc2ndIndex < suballoc2ndCount)
- {
- const Suballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
- // 1. Process free space before this allocation.
- if (lastOffset < suballoc.offset)
- {
- // There is free space from lastOffset to suballoc.offset.
- ++unusedRangeCount;
- }
- // 2. Process this allocation.
- // There is allocation with suballoc.offset, suballoc.size.
- ++alloc2ndCount;
- usedBytes += suballoc.size;
- // 3. Prepare for next iteration.
- lastOffset = suballoc.offset + suballoc.size;
- ++nextAlloc2ndIndex;
- }
- // We are at the end.
- else
- {
- if (lastOffset < freeSpace2ndTo1stEnd)
- {
- // There is free space from lastOffset to freeSpace2ndTo1stEnd.
- ++unusedRangeCount;
- }
- // End of loop.
- lastOffset = freeSpace2ndTo1stEnd;
- }
- }
- }
- size_t nextAlloc1stIndex = m_1stNullItemsBeginCount;
- size_t alloc1stCount = 0;
- const UINT64 freeSpace1stTo2ndEnd =
- m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ? suballocations2nd.back().offset : size;
- while (lastOffset < freeSpace1stTo2ndEnd)
- {
- // Find next non-null allocation or move nextAllocIndex to the end.
- while (nextAlloc1stIndex < suballoc1stCount &&
- suballocations1st[nextAlloc1stIndex].privateData == NULL)
- {
- ++nextAlloc1stIndex;
- }
- // Found non-null allocation.
- if (nextAlloc1stIndex < suballoc1stCount)
- {
- const Suballocation& suballoc = suballocations1st[nextAlloc1stIndex];
- // 1. Process free space before this allocation.
- if (lastOffset < suballoc.offset)
- {
- // There is free space from lastOffset to suballoc.offset.
- ++unusedRangeCount;
- }
- // 2. Process this allocation.
- // There is allocation with suballoc.offset, suballoc.size.
- ++alloc1stCount;
- usedBytes += suballoc.size;
- // 3. Prepare for next iteration.
- lastOffset = suballoc.offset + suballoc.size;
- ++nextAlloc1stIndex;
- }
- // We are at the end.
- else
- {
- if (lastOffset < size)
- {
- // There is free space from lastOffset to freeSpace1stTo2ndEnd.
- ++unusedRangeCount;
- }
- // End of loop.
- lastOffset = freeSpace1stTo2ndEnd;
- }
- }
- if (m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
- {
- size_t nextAlloc2ndIndex = suballocations2nd.size() - 1;
- while (lastOffset < size)
- {
- // Find next non-null allocation or move nextAlloc2ndIndex to the end.
- while (nextAlloc2ndIndex != SIZE_MAX &&
- suballocations2nd[nextAlloc2ndIndex].privateData == NULL)
- {
- --nextAlloc2ndIndex;
- }
- // Found non-null allocation.
- if (nextAlloc2ndIndex != SIZE_MAX)
- {
- const Suballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
- // 1. Process free space before this allocation.
- if (lastOffset < suballoc.offset)
- {
- // There is free space from lastOffset to suballoc.offset.
- ++unusedRangeCount;
- }
- // 2. Process this allocation.
- // There is allocation with suballoc.offset, suballoc.size.
- ++alloc2ndCount;
- usedBytes += suballoc.size;
- // 3. Prepare for next iteration.
- lastOffset = suballoc.offset + suballoc.size;
- --nextAlloc2ndIndex;
- }
- // We are at the end.
- else
- {
- if (lastOffset < size)
- {
- // There is free space from lastOffset to size.
- ++unusedRangeCount;
- }
- // End of loop.
- lastOffset = size;
- }
- }
- }
- const UINT64 unusedBytes = size - usedBytes;
- PrintDetailedMap_Begin(json, unusedBytes, alloc1stCount + alloc2ndCount, unusedRangeCount);
- // SECOND PASS
- lastOffset = 0;
- if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
- {
- const UINT64 freeSpace2ndTo1stEnd = suballocations1st[m_1stNullItemsBeginCount].offset;
- size_t nextAlloc2ndIndex = 0;
- while (lastOffset < freeSpace2ndTo1stEnd)
- {
- // Find next non-null allocation or move nextAlloc2ndIndex to the end.
- while (nextAlloc2ndIndex < suballoc2ndCount &&
- suballocations2nd[nextAlloc2ndIndex].privateData == NULL)
- {
- ++nextAlloc2ndIndex;
- }
- // Found non-null allocation.
- if (nextAlloc2ndIndex < suballoc2ndCount)
- {
- const Suballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
- // 1. Process free space before this allocation.
- if (lastOffset < suballoc.offset)
- {
- // There is free space from lastOffset to suballoc.offset.
- const UINT64 unusedRangeSize = suballoc.offset - lastOffset;
- PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
- }
- // 2. Process this allocation.
- // There is allocation with suballoc.offset, suballoc.size.
- PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.privateData);
- // 3. Prepare for next iteration.
- lastOffset = suballoc.offset + suballoc.size;
- ++nextAlloc2ndIndex;
- }
- // We are at the end.
- else
- {
- if (lastOffset < freeSpace2ndTo1stEnd)
- {
- // There is free space from lastOffset to freeSpace2ndTo1stEnd.
- const UINT64 unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset;
- PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
- }
- // End of loop.
- lastOffset = freeSpace2ndTo1stEnd;
- }
- }
- }
- nextAlloc1stIndex = m_1stNullItemsBeginCount;
- while (lastOffset < freeSpace1stTo2ndEnd)
- {
- // Find next non-null allocation or move nextAllocIndex to the end.
- while (nextAlloc1stIndex < suballoc1stCount &&
- suballocations1st[nextAlloc1stIndex].privateData == NULL)
- {
- ++nextAlloc1stIndex;
- }
- // Found non-null allocation.
- if (nextAlloc1stIndex < suballoc1stCount)
- {
- const Suballocation& suballoc = suballocations1st[nextAlloc1stIndex];
- // 1. Process free space before this allocation.
- if (lastOffset < suballoc.offset)
- {
- // There is free space from lastOffset to suballoc.offset.
- const UINT64 unusedRangeSize = suballoc.offset - lastOffset;
- PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
- }
- // 2. Process this allocation.
- // There is allocation with suballoc.offset, suballoc.size.
- PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.privateData);
- // 3. Prepare for next iteration.
- lastOffset = suballoc.offset + suballoc.size;
- ++nextAlloc1stIndex;
- }
- // We are at the end.
- else
- {
- if (lastOffset < freeSpace1stTo2ndEnd)
- {
- // There is free space from lastOffset to freeSpace1stTo2ndEnd.
- const UINT64 unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset;
- PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
- }
- // End of loop.
- lastOffset = freeSpace1stTo2ndEnd;
- }
- }
- if (m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
- {
- size_t nextAlloc2ndIndex = suballocations2nd.size() - 1;
- while (lastOffset < size)
- {
- // Find next non-null allocation or move nextAlloc2ndIndex to the end.
- while (nextAlloc2ndIndex != SIZE_MAX &&
- suballocations2nd[nextAlloc2ndIndex].privateData == NULL)
- {
- --nextAlloc2ndIndex;
- }
- // Found non-null allocation.
- if (nextAlloc2ndIndex != SIZE_MAX)
- {
- const Suballocation& suballoc = suballocations2nd[nextAlloc2ndIndex];
- // 1. Process free space before this allocation.
- if (lastOffset < suballoc.offset)
- {
- // There is free space from lastOffset to suballoc.offset.
- const UINT64 unusedRangeSize = suballoc.offset - lastOffset;
- PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
- }
- // 2. Process this allocation.
- // There is allocation with suballoc.offset, suballoc.size.
- PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.privateData);
- // 3. Prepare for next iteration.
- lastOffset = suballoc.offset + suballoc.size;
- --nextAlloc2ndIndex;
- }
- // We are at the end.
- else
- {
- if (lastOffset < size)
- {
- // There is free space from lastOffset to size.
- const UINT64 unusedRangeSize = size - lastOffset;
- PrintDetailedMap_UnusedRange(json, lastOffset, unusedRangeSize);
- }
- // End of loop.
- lastOffset = size;
- }
- }
- }
- PrintDetailedMap_End(json);
- }
- void BlockMetadata_Linear::DebugLogAllAllocations() const
- {
- const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
- for (auto it = suballocations1st.begin() + m_1stNullItemsBeginCount; it != suballocations1st.end(); ++it)
- if (it->type != SUBALLOCATION_TYPE_FREE)
- DebugLogAllocation(it->offset, it->size, it->privateData);
- const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
- for (auto it = suballocations2nd.begin(); it != suballocations2nd.end(); ++it)
- if (it->type != SUBALLOCATION_TYPE_FREE)
- DebugLogAllocation(it->offset, it->size, it->privateData);
- }
- Suballocation& BlockMetadata_Linear::FindSuballocation(UINT64 offset) const
- {
- const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
- const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
- Suballocation refSuballoc;
- refSuballoc.offset = offset;
- // Rest of members stays uninitialized intentionally for better performance.
- // Item from the 1st vector.
- {
- const SuballocationVectorType::const_iterator it = BinaryFindSorted(
- suballocations1st.begin() + m_1stNullItemsBeginCount,
- suballocations1st.end(),
- refSuballoc,
- SuballocationOffsetLess());
- if (it != suballocations1st.end())
- {
- return const_cast<Suballocation&>(*it);
- }
- }
- if (m_2ndVectorMode != SECOND_VECTOR_EMPTY)
- {
- // Rest of members stays uninitialized intentionally for better performance.
- const SuballocationVectorType::const_iterator it = m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER ?
- BinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, SuballocationOffsetLess()) :
- BinaryFindSorted(suballocations2nd.begin(), suballocations2nd.end(), refSuballoc, SuballocationOffsetGreater());
- if (it != suballocations2nd.end())
- {
- return const_cast<Suballocation&>(*it);
- }
- }
- D3D12MA_ASSERT(0 && "Allocation not found in linear allocator!");
- return const_cast<Suballocation&>(suballocations1st.back()); // Should never occur.
- }
- bool BlockMetadata_Linear::ShouldCompact1st() const
- {
- const size_t nullItemCount = m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount;
- const size_t suballocCount = AccessSuballocations1st().size();
- return suballocCount > 32 && nullItemCount * 2 >= (suballocCount - nullItemCount) * 3;
- }
- void BlockMetadata_Linear::CleanupAfterFree()
- {
- SuballocationVectorType& suballocations1st = AccessSuballocations1st();
- SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
- if (IsEmpty())
- {
- suballocations1st.clear();
- suballocations2nd.clear();
- m_1stNullItemsBeginCount = 0;
- m_1stNullItemsMiddleCount = 0;
- m_2ndNullItemsCount = 0;
- m_2ndVectorMode = SECOND_VECTOR_EMPTY;
- }
- else
- {
- const size_t suballoc1stCount = suballocations1st.size();
- const size_t nullItem1stCount = m_1stNullItemsBeginCount + m_1stNullItemsMiddleCount;
- D3D12MA_ASSERT(nullItem1stCount <= suballoc1stCount);
- // Find more null items at the beginning of 1st vector.
- while (m_1stNullItemsBeginCount < suballoc1stCount &&
- suballocations1st[m_1stNullItemsBeginCount].type == SUBALLOCATION_TYPE_FREE)
- {
- ++m_1stNullItemsBeginCount;
- --m_1stNullItemsMiddleCount;
- }
- // Find more null items at the end of 1st vector.
- while (m_1stNullItemsMiddleCount > 0 &&
- suballocations1st.back().type == SUBALLOCATION_TYPE_FREE)
- {
- --m_1stNullItemsMiddleCount;
- suballocations1st.pop_back();
- }
- // Find more null items at the end of 2nd vector.
- while (m_2ndNullItemsCount > 0 &&
- suballocations2nd.back().type == SUBALLOCATION_TYPE_FREE)
- {
- --m_2ndNullItemsCount;
- suballocations2nd.pop_back();
- }
- // Find more null items at the beginning of 2nd vector.
- while (m_2ndNullItemsCount > 0 &&
- suballocations2nd[0].type == SUBALLOCATION_TYPE_FREE)
- {
- --m_2ndNullItemsCount;
- suballocations2nd.remove(0);
- }
- if (ShouldCompact1st())
- {
- const size_t nonNullItemCount = suballoc1stCount - nullItem1stCount;
- size_t srcIndex = m_1stNullItemsBeginCount;
- for (size_t dstIndex = 0; dstIndex < nonNullItemCount; ++dstIndex)
- {
- while (suballocations1st[srcIndex].type == SUBALLOCATION_TYPE_FREE)
- {
- ++srcIndex;
- }
- if (dstIndex != srcIndex)
- {
- suballocations1st[dstIndex] = suballocations1st[srcIndex];
- }
- ++srcIndex;
- }
- suballocations1st.resize(nonNullItemCount);
- m_1stNullItemsBeginCount = 0;
- m_1stNullItemsMiddleCount = 0;
- }
- // 2nd vector became empty.
- if (suballocations2nd.empty())
- {
- m_2ndVectorMode = SECOND_VECTOR_EMPTY;
- }
- // 1st vector became empty.
- if (suballocations1st.size() - m_1stNullItemsBeginCount == 0)
- {
- suballocations1st.clear();
- m_1stNullItemsBeginCount = 0;
- if (!suballocations2nd.empty() && m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
- {
- // Swap 1st with 2nd. Now 2nd is empty.
- m_2ndVectorMode = SECOND_VECTOR_EMPTY;
- m_1stNullItemsMiddleCount = m_2ndNullItemsCount;
- while (m_1stNullItemsBeginCount < suballocations2nd.size() &&
- suballocations2nd[m_1stNullItemsBeginCount].type == SUBALLOCATION_TYPE_FREE)
- {
- ++m_1stNullItemsBeginCount;
- --m_1stNullItemsMiddleCount;
- }
- m_2ndNullItemsCount = 0;
- m_1stVectorIndex ^= 1;
- }
- }
- }
- D3D12MA_HEAVY_ASSERT(Validate());
- }
- bool BlockMetadata_Linear::CreateAllocationRequest_LowerAddress(
- UINT64 allocSize,
- UINT64 allocAlignment,
- AllocationRequest* pAllocationRequest)
- {
- const UINT64 blockSize = GetSize();
- SuballocationVectorType& suballocations1st = AccessSuballocations1st();
- SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
- if (m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK)
- {
- // Try to allocate at the end of 1st vector.
- UINT64 resultBaseOffset = 0;
- if (!suballocations1st.empty())
- {
- const Suballocation& lastSuballoc = suballocations1st.back();
- resultBaseOffset = lastSuballoc.offset + lastSuballoc.size + GetDebugMargin();
- }
- // Start from offset equal to beginning of free space.
- UINT64 resultOffset = resultBaseOffset;
- // Apply alignment.
- resultOffset = AlignUp(resultOffset, allocAlignment);
- const UINT64 freeSpaceEnd = m_2ndVectorMode == SECOND_VECTOR_DOUBLE_STACK ?
- suballocations2nd.back().offset : blockSize;
- // There is enough free space at the end after alignment.
- if (resultOffset + allocSize + GetDebugMargin() <= freeSpaceEnd)
- {
- // All tests passed: Success.
- pAllocationRequest->allocHandle = (AllocHandle)(resultOffset + 1);
- // pAllocationRequest->item, customData unused.
- pAllocationRequest->algorithmData = ALLOC_REQUEST_END_OF_1ST;
- return true;
- }
- }
- // Wrap-around to end of 2nd vector. Try to allocate there, watching for the
- // beginning of 1st vector as the end of free space.
- if (m_2ndVectorMode == SECOND_VECTOR_EMPTY || m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
- {
- D3D12MA_ASSERT(!suballocations1st.empty());
- UINT64 resultBaseOffset = 0;
- if (!suballocations2nd.empty())
- {
- const Suballocation& lastSuballoc = suballocations2nd.back();
- resultBaseOffset = lastSuballoc.offset + lastSuballoc.size + GetDebugMargin();
- }
- // Start from offset equal to beginning of free space.
- UINT64 resultOffset = resultBaseOffset;
- // Apply alignment.
- resultOffset = AlignUp(resultOffset, allocAlignment);
- size_t index1st = m_1stNullItemsBeginCount;
- // There is enough free space at the end after alignment.
- if ((index1st == suballocations1st.size() && resultOffset + allocSize + GetDebugMargin() <= blockSize) ||
- (index1st < suballocations1st.size() && resultOffset + allocSize + GetDebugMargin() <= suballocations1st[index1st].offset))
- {
- // All tests passed: Success.
- pAllocationRequest->allocHandle = (AllocHandle)(resultOffset + 1);
- pAllocationRequest->algorithmData = ALLOC_REQUEST_END_OF_2ND;
- // pAllocationRequest->item, customData unused.
- return true;
- }
- }
- return false;
- }
- bool BlockMetadata_Linear::CreateAllocationRequest_UpperAddress(
- UINT64 allocSize,
- UINT64 allocAlignment,
- AllocationRequest* pAllocationRequest)
- {
- const UINT64 blockSize = GetSize();
- SuballocationVectorType& suballocations1st = AccessSuballocations1st();
- SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
- if (m_2ndVectorMode == SECOND_VECTOR_RING_BUFFER)
- {
- D3D12MA_ASSERT(0 && "Trying to use pool with linear algorithm as double stack, while it is already being used as ring buffer.");
- return false;
- }
- // Try to allocate before 2nd.back(), or end of block if 2nd.empty().
- if (allocSize > blockSize)
- {
- return false;
- }
- UINT64 resultBaseOffset = blockSize - allocSize;
- if (!suballocations2nd.empty())
- {
- const Suballocation& lastSuballoc = suballocations2nd.back();
- resultBaseOffset = lastSuballoc.offset - allocSize;
- if (allocSize > lastSuballoc.offset)
- {
- return false;
- }
- }
- // Start from offset equal to end of free space.
- UINT64 resultOffset = resultBaseOffset;
- // Apply debugMargin at the end.
- if (GetDebugMargin() > 0)
- {
- if (resultOffset < GetDebugMargin())
- {
- return false;
- }
- resultOffset -= GetDebugMargin();
- }
- // Apply alignment.
- resultOffset = AlignDown(resultOffset, allocAlignment);
- // There is enough free space.
- const UINT64 endOf1st = !suballocations1st.empty() ?
- suballocations1st.back().offset + suballocations1st.back().size : 0;
- if (endOf1st + GetDebugMargin() <= resultOffset)
- {
- // All tests passed: Success.
- pAllocationRequest->allocHandle = (AllocHandle)(resultOffset + 1);
- // pAllocationRequest->item unused.
- pAllocationRequest->algorithmData = ALLOC_REQUEST_UPPER_ADDRESS;
- return true;
- }
- return false;
- }
- #endif // _D3D12MA_BLOCK_METADATA_LINEAR_FUNCTIONS
- #endif // _D3D12MA_BLOCK_METADATA_LINEAR
- #ifndef _D3D12MA_BLOCK_METADATA_TLSF
- class BlockMetadata_TLSF : public BlockMetadata
- {
- public:
- BlockMetadata_TLSF(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual);
- virtual ~BlockMetadata_TLSF();
- size_t GetAllocationCount() const override { return m_AllocCount; }
- size_t GetFreeRegionsCount() const override { return m_BlocksFreeCount + 1; }
- UINT64 GetSumFreeSize() const override { return m_BlocksFreeSize + m_NullBlock->size; }
- bool IsEmpty() const override { return m_NullBlock->offset == 0; }
- UINT64 GetAllocationOffset(AllocHandle allocHandle) const override { return ((Block*)allocHandle)->offset; };
- void Init(UINT64 size) override;
- bool Validate() const override;
- void GetAllocationInfo(AllocHandle allocHandle, VIRTUAL_ALLOCATION_INFO& outInfo) const override;
- bool CreateAllocationRequest(
- UINT64 allocSize,
- UINT64 allocAlignment,
- bool upperAddress,
- UINT32 strategy,
- AllocationRequest* pAllocationRequest) override;
- void Alloc(
- const AllocationRequest& request,
- UINT64 allocSize,
- void* privateData) override;
- void Free(AllocHandle allocHandle) override;
- void Clear() override;
- AllocHandle GetAllocationListBegin() const override;
- AllocHandle GetNextAllocation(AllocHandle prevAlloc) const override;
- UINT64 GetNextFreeRegionSize(AllocHandle alloc) const override;
- void* GetAllocationPrivateData(AllocHandle allocHandle) const override;
- void SetAllocationPrivateData(AllocHandle allocHandle, void* privateData) override;
- void AddStatistics(Statistics& inoutStats) const override;
- void AddDetailedStatistics(DetailedStatistics& inoutStats) const override;
- void WriteAllocationInfoToJson(JsonWriter& json) const override;
- void DebugLogAllAllocations() const override;
- private:
- // According to original paper it should be preferable 4 or 5:
- // M. Masmano, I. Ripoll, A. Crespo, and J. Real "TLSF: a New Dynamic Memory Allocator for Real-Time Systems"
- // http://www.gii.upv.es/tlsf/files/ecrts04_tlsf.pdf
- static const UINT8 SECOND_LEVEL_INDEX = 5;
- static const UINT16 SMALL_BUFFER_SIZE = 256;
- static const UINT INITIAL_BLOCK_ALLOC_COUNT = 16;
- static const UINT8 MEMORY_CLASS_SHIFT = 7;
- static const UINT8 MAX_MEMORY_CLASSES = 65 - MEMORY_CLASS_SHIFT;
- class Block
- {
- public:
- UINT64 offset;
- UINT64 size;
- Block* prevPhysical;
- Block* nextPhysical;
- void MarkFree() { prevFree = NULL; }
- void MarkTaken() { prevFree = this; }
- bool IsFree() const { return prevFree != this; }
- void*& PrivateData() { D3D12MA_HEAVY_ASSERT(!IsFree()); return privateData; }
- Block*& PrevFree() { return prevFree; }
- Block*& NextFree() { D3D12MA_HEAVY_ASSERT(IsFree()); return nextFree; }
- private:
- Block* prevFree; // Address of the same block here indicates that block is taken
- union
- {
- Block* nextFree;
- void* privateData;
- };
- };
-
- size_t m_AllocCount = 0;
- // Total number of free blocks besides null block
- size_t m_BlocksFreeCount = 0;
- // Total size of free blocks excluding null block
- UINT64 m_BlocksFreeSize = 0;
- UINT32 m_IsFreeBitmap = 0;
- UINT8 m_MemoryClasses = 0;
- UINT32 m_InnerIsFreeBitmap[MAX_MEMORY_CLASSES];
- UINT32 m_ListsCount = 0;
- /*
- * 0: 0-3 lists for small buffers
- * 1+: 0-(2^SLI-1) lists for normal buffers
- */
- Block** m_FreeList = NULL;
- PoolAllocator<Block> m_BlockAllocator;
- Block* m_NullBlock = NULL;
- UINT8 SizeToMemoryClass(UINT64 size) const;
- UINT16 SizeToSecondIndex(UINT64 size, UINT8 memoryClass) const;
- UINT32 GetListIndex(UINT8 memoryClass, UINT16 secondIndex) const;
- UINT32 GetListIndex(UINT64 size) const;
- void RemoveFreeBlock(Block* block);
- void InsertFreeBlock(Block* block);
- void MergeBlock(Block* block, Block* prev);
- Block* FindFreeBlock(UINT64 size, UINT32& listIndex) const;
- bool CheckBlock(
- Block& block,
- UINT32 listIndex,
- UINT64 allocSize,
- UINT64 allocAlignment,
- AllocationRequest* pAllocationRequest);
- D3D12MA_CLASS_NO_COPY(BlockMetadata_TLSF)
- };
- #ifndef _D3D12MA_BLOCK_METADATA_TLSF_FUNCTIONS
- BlockMetadata_TLSF::BlockMetadata_TLSF(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual)
- : BlockMetadata(allocationCallbacks, isVirtual),
- m_BlockAllocator(*allocationCallbacks, INITIAL_BLOCK_ALLOC_COUNT)
- {
- D3D12MA_ASSERT(allocationCallbacks);
- }
- BlockMetadata_TLSF::~BlockMetadata_TLSF()
- {
- D3D12MA_DELETE_ARRAY(*GetAllocs(), m_FreeList, m_ListsCount);
- }
- void BlockMetadata_TLSF::Init(UINT64 size)
- {
- BlockMetadata::Init(size);
- m_NullBlock = m_BlockAllocator.Alloc();
- m_NullBlock->size = size;
- m_NullBlock->offset = 0;
- m_NullBlock->prevPhysical = NULL;
- m_NullBlock->nextPhysical = NULL;
- m_NullBlock->MarkFree();
- m_NullBlock->NextFree() = NULL;
- m_NullBlock->PrevFree() = NULL;
- UINT8 memoryClass = SizeToMemoryClass(size);
- UINT16 sli = SizeToSecondIndex(size, memoryClass);
- m_ListsCount = (memoryClass == 0 ? 0 : (memoryClass - 1) * (1UL << SECOND_LEVEL_INDEX) + sli) + 1;
- if (IsVirtual())
- m_ListsCount += 1UL << SECOND_LEVEL_INDEX;
- else
- m_ListsCount += 4;
- m_MemoryClasses = memoryClass + 2;
- memset(m_InnerIsFreeBitmap, 0, MAX_MEMORY_CLASSES * sizeof(UINT32));
- m_FreeList = D3D12MA_NEW_ARRAY(*GetAllocs(), Block*, m_ListsCount);
- memset(m_FreeList, 0, m_ListsCount * sizeof(Block*));
- }
- bool BlockMetadata_TLSF::Validate() const
- {
- D3D12MA_VALIDATE(GetSumFreeSize() <= GetSize());
- UINT64 calculatedSize = m_NullBlock->size;
- UINT64 calculatedFreeSize = m_NullBlock->size;
- size_t allocCount = 0;
- size_t freeCount = 0;
- // Check integrity of free lists
- for (UINT32 list = 0; list < m_ListsCount; ++list)
- {
- Block* block = m_FreeList[list];
- if (block != NULL)
- {
- D3D12MA_VALIDATE(block->IsFree());
- D3D12MA_VALIDATE(block->PrevFree() == NULL);
- while (block->NextFree())
- {
- D3D12MA_VALIDATE(block->NextFree()->IsFree());
- D3D12MA_VALIDATE(block->NextFree()->PrevFree() == block);
- block = block->NextFree();
- }
- }
- }
- D3D12MA_VALIDATE(m_NullBlock->nextPhysical == NULL);
- if (m_NullBlock->prevPhysical)
- {
- D3D12MA_VALIDATE(m_NullBlock->prevPhysical->nextPhysical == m_NullBlock);
- }
- // Check all blocks
- UINT64 nextOffset = m_NullBlock->offset;
- for (Block* prev = m_NullBlock->prevPhysical; prev != NULL; prev = prev->prevPhysical)
- {
- D3D12MA_VALIDATE(prev->offset + prev->size == nextOffset);
- nextOffset = prev->offset;
- calculatedSize += prev->size;
- UINT32 listIndex = GetListIndex(prev->size);
- if (prev->IsFree())
- {
- ++freeCount;
- // Check if free block belongs to free list
- Block* freeBlock = m_FreeList[listIndex];
- D3D12MA_VALIDATE(freeBlock != NULL);
- bool found = false;
- do
- {
- if (freeBlock == prev)
- found = true;
- freeBlock = freeBlock->NextFree();
- } while (!found && freeBlock != NULL);
- D3D12MA_VALIDATE(found);
- calculatedFreeSize += prev->size;
- }
- else
- {
- ++allocCount;
- // Check if taken block is not on a free list
- Block* freeBlock = m_FreeList[listIndex];
- while (freeBlock)
- {
- D3D12MA_VALIDATE(freeBlock != prev);
- freeBlock = freeBlock->NextFree();
- }
- }
- if (prev->prevPhysical)
- {
- D3D12MA_VALIDATE(prev->prevPhysical->nextPhysical == prev);
- }
- }
- D3D12MA_VALIDATE(nextOffset == 0);
- D3D12MA_VALIDATE(calculatedSize == GetSize());
- D3D12MA_VALIDATE(calculatedFreeSize == GetSumFreeSize());
- D3D12MA_VALIDATE(allocCount == m_AllocCount);
- D3D12MA_VALIDATE(freeCount == m_BlocksFreeCount);
- return true;
- }
- void BlockMetadata_TLSF::GetAllocationInfo(AllocHandle allocHandle, VIRTUAL_ALLOCATION_INFO& outInfo) const
- {
- Block* block = (Block*)allocHandle;
- D3D12MA_ASSERT(!block->IsFree() && "Cannot get allocation info for free block!");
- outInfo.Offset = block->offset;
- outInfo.Size = block->size;
- outInfo.pPrivateData = block->PrivateData();
- }
- bool BlockMetadata_TLSF::CreateAllocationRequest(
- UINT64 allocSize,
- UINT64 allocAlignment,
- bool upperAddress,
- UINT32 strategy,
- AllocationRequest* pAllocationRequest)
- {
- D3D12MA_ASSERT(allocSize > 0 && "Cannot allocate empty block!");
- D3D12MA_ASSERT(!upperAddress && "ALLOCATION_FLAG_UPPER_ADDRESS can be used only with linear algorithm.");
- D3D12MA_ASSERT(pAllocationRequest != NULL);
- D3D12MA_HEAVY_ASSERT(Validate());
- allocSize += GetDebugMargin();
- // Quick check for too small pool
- if (allocSize > GetSumFreeSize())
- return false;
- // If no free blocks in pool then check only null block
- if (m_BlocksFreeCount == 0)
- return CheckBlock(*m_NullBlock, m_ListsCount, allocSize, allocAlignment, pAllocationRequest);
- // Round up to the next block
- UINT64 sizeForNextList = allocSize;
- UINT16 smallSizeStep = SMALL_BUFFER_SIZE / (IsVirtual() ? 1 << SECOND_LEVEL_INDEX : 4);
- if (allocSize > SMALL_BUFFER_SIZE)
- {
- sizeForNextList += (1ULL << (BitScanMSB(allocSize) - SECOND_LEVEL_INDEX));
- }
- else if (allocSize > SMALL_BUFFER_SIZE - smallSizeStep)
- sizeForNextList = SMALL_BUFFER_SIZE + 1;
- else
- sizeForNextList += smallSizeStep;
- UINT32 nextListIndex = 0;
- UINT32 prevListIndex = 0;
- Block* nextListBlock = NULL;
- Block* prevListBlock = NULL;
- // Check blocks according to strategies
- if (strategy & ALLOCATION_FLAG_STRATEGY_MIN_TIME)
- {
- // Quick check for larger block first
- nextListBlock = FindFreeBlock(sizeForNextList, nextListIndex);
- if (nextListBlock != NULL && CheckBlock(*nextListBlock, nextListIndex, allocSize, allocAlignment, pAllocationRequest))
- return true;
- // If not fitted then null block
- if (CheckBlock(*m_NullBlock, m_ListsCount, allocSize, allocAlignment, pAllocationRequest))
- return true;
- // Null block failed, search larger bucket
- while (nextListBlock)
- {
- if (CheckBlock(*nextListBlock, nextListIndex, allocSize, allocAlignment, pAllocationRequest))
- return true;
- nextListBlock = nextListBlock->NextFree();
- }
- // Failed again, check best fit bucket
- prevListBlock = FindFreeBlock(allocSize, prevListIndex);
- while (prevListBlock)
- {
- if (CheckBlock(*prevListBlock, prevListIndex, allocSize, allocAlignment, pAllocationRequest))
- return true;
- prevListBlock = prevListBlock->NextFree();
- }
- }
- else if (strategy & ALLOCATION_FLAG_STRATEGY_MIN_MEMORY)
- {
- // Check best fit bucket
- prevListBlock = FindFreeBlock(allocSize, prevListIndex);
- while (prevListBlock)
- {
- if (CheckBlock(*prevListBlock, prevListIndex, allocSize, allocAlignment, pAllocationRequest))
- return true;
- prevListBlock = prevListBlock->NextFree();
- }
- // If failed check null block
- if (CheckBlock(*m_NullBlock, m_ListsCount, allocSize, allocAlignment, pAllocationRequest))
- return true;
- // Check larger bucket
- nextListBlock = FindFreeBlock(sizeForNextList, nextListIndex);
- while (nextListBlock)
- {
- if (CheckBlock(*nextListBlock, nextListIndex, allocSize, allocAlignment, pAllocationRequest))
- return true;
- nextListBlock = nextListBlock->NextFree();
- }
- }
- else if (strategy & ALLOCATION_FLAG_STRATEGY_MIN_OFFSET)
- {
- // Perform search from the start
- Vector<Block*> blockList(m_BlocksFreeCount, *GetAllocs());
- size_t i = m_BlocksFreeCount;
- for (Block* block = m_NullBlock->prevPhysical; block != NULL; block = block->prevPhysical)
- {
- if (block->IsFree() && block->size >= allocSize)
- blockList[--i] = block;
- }
- for (; i < m_BlocksFreeCount; ++i)
- {
- Block& block = *blockList[i];
- if (CheckBlock(block, GetListIndex(block.size), allocSize, allocAlignment, pAllocationRequest))
- return true;
- }
- // If failed check null block
- if (CheckBlock(*m_NullBlock, m_ListsCount, allocSize, allocAlignment, pAllocationRequest))
- return true;
- // Whole range searched, no more memory
- return false;
- }
- else
- {
- // Check larger bucket
- nextListBlock = FindFreeBlock(sizeForNextList, nextListIndex);
- while (nextListBlock)
- {
- if (CheckBlock(*nextListBlock, nextListIndex, allocSize, allocAlignment, pAllocationRequest))
- return true;
- nextListBlock = nextListBlock->NextFree();
- }
- // If failed check null block
- if (CheckBlock(*m_NullBlock, m_ListsCount, allocSize, allocAlignment, pAllocationRequest))
- return true;
- // Check best fit bucket
- prevListBlock = FindFreeBlock(allocSize, prevListIndex);
- while (prevListBlock)
- {
- if (CheckBlock(*prevListBlock, prevListIndex, allocSize, allocAlignment, pAllocationRequest))
- return true;
- prevListBlock = prevListBlock->NextFree();
- }
- }
- // Worst case, full search has to be done
- while (++nextListIndex < m_ListsCount)
- {
- nextListBlock = m_FreeList[nextListIndex];
- while (nextListBlock)
- {
- if (CheckBlock(*nextListBlock, nextListIndex, allocSize, allocAlignment, pAllocationRequest))
- return true;
- nextListBlock = nextListBlock->NextFree();
- }
- }
- // No more memory sadly
- return false;
- }
- void BlockMetadata_TLSF::Alloc(
- const AllocationRequest& request,
- UINT64 allocSize,
- void* privateData)
- {
- // Get block and pop it from the free list
- Block* currentBlock = (Block*)request.allocHandle;
- UINT64 offset = request.algorithmData;
- D3D12MA_ASSERT(currentBlock != NULL);
- D3D12MA_ASSERT(currentBlock->offset <= offset);
- if (currentBlock != m_NullBlock)
- RemoveFreeBlock(currentBlock);
- // Append missing alignment to prev block or create new one
- UINT64 misssingAlignment = offset - currentBlock->offset;
- if (misssingAlignment)
- {
- Block* prevBlock = currentBlock->prevPhysical;
- D3D12MA_ASSERT(prevBlock != NULL && "There should be no missing alignment at offset 0!");
- if (prevBlock->IsFree() && prevBlock->size != GetDebugMargin())
- {
- UINT32 oldList = GetListIndex(prevBlock->size);
- prevBlock->size += misssingAlignment;
- // Check if new size crosses list bucket
- if (oldList != GetListIndex(prevBlock->size))
- {
- prevBlock->size -= misssingAlignment;
- RemoveFreeBlock(prevBlock);
- prevBlock->size += misssingAlignment;
- InsertFreeBlock(prevBlock);
- }
- else
- m_BlocksFreeSize += misssingAlignment;
- }
- else
- {
- Block* newBlock = m_BlockAllocator.Alloc();
- currentBlock->prevPhysical = newBlock;
- prevBlock->nextPhysical = newBlock;
- newBlock->prevPhysical = prevBlock;
- newBlock->nextPhysical = currentBlock;
- newBlock->size = misssingAlignment;
- newBlock->offset = currentBlock->offset;
- newBlock->MarkTaken();
- InsertFreeBlock(newBlock);
- }
- currentBlock->size -= misssingAlignment;
- currentBlock->offset += misssingAlignment;
- }
- UINT64 size = request.size + GetDebugMargin();
- if (currentBlock->size == size)
- {
- if (currentBlock == m_NullBlock)
- {
- // Setup new null block
- m_NullBlock = m_BlockAllocator.Alloc();
- m_NullBlock->size = 0;
- m_NullBlock->offset = currentBlock->offset + size;
- m_NullBlock->prevPhysical = currentBlock;
- m_NullBlock->nextPhysical = NULL;
- m_NullBlock->MarkFree();
- m_NullBlock->PrevFree() = NULL;
- m_NullBlock->NextFree() = NULL;
- currentBlock->nextPhysical = m_NullBlock;
- currentBlock->MarkTaken();
- }
- }
- else
- {
- D3D12MA_ASSERT(currentBlock->size > size && "Proper block already found, shouldn't find smaller one!");
- // Create new free block
- Block* newBlock = m_BlockAllocator.Alloc();
- newBlock->size = currentBlock->size - size;
- newBlock->offset = currentBlock->offset + size;
- newBlock->prevPhysical = currentBlock;
- newBlock->nextPhysical = currentBlock->nextPhysical;
- currentBlock->nextPhysical = newBlock;
- currentBlock->size = size;
- if (currentBlock == m_NullBlock)
- {
- m_NullBlock = newBlock;
- m_NullBlock->MarkFree();
- m_NullBlock->NextFree() = NULL;
- m_NullBlock->PrevFree() = NULL;
- currentBlock->MarkTaken();
- }
- else
- {
- newBlock->nextPhysical->prevPhysical = newBlock;
- newBlock->MarkTaken();
- InsertFreeBlock(newBlock);
- }
- }
- currentBlock->PrivateData() = privateData;
- if (GetDebugMargin() > 0)
- {
- currentBlock->size -= GetDebugMargin();
- Block* newBlock = m_BlockAllocator.Alloc();
- newBlock->size = GetDebugMargin();
- newBlock->offset = currentBlock->offset + currentBlock->size;
- newBlock->prevPhysical = currentBlock;
- newBlock->nextPhysical = currentBlock->nextPhysical;
- newBlock->MarkTaken();
- currentBlock->nextPhysical->prevPhysical = newBlock;
- currentBlock->nextPhysical = newBlock;
- InsertFreeBlock(newBlock);
- }
- ++m_AllocCount;
- }
- void BlockMetadata_TLSF::Free(AllocHandle allocHandle)
- {
- Block* block = (Block*)allocHandle;
- Block* next = block->nextPhysical;
- D3D12MA_ASSERT(!block->IsFree() && "Block is already free!");
- --m_AllocCount;
- if (GetDebugMargin() > 0)
- {
- RemoveFreeBlock(next);
- MergeBlock(next, block);
- block = next;
- next = next->nextPhysical;
- }
- // Try merging
- Block* prev = block->prevPhysical;
- if (prev != NULL && prev->IsFree() && prev->size != GetDebugMargin())
- {
- RemoveFreeBlock(prev);
- MergeBlock(block, prev);
- }
- if (!next->IsFree())
- InsertFreeBlock(block);
- else if (next == m_NullBlock)
- MergeBlock(m_NullBlock, block);
- else
- {
- RemoveFreeBlock(next);
- MergeBlock(next, block);
- InsertFreeBlock(next);
- }
- }
- void BlockMetadata_TLSF::Clear()
- {
- m_AllocCount = 0;
- m_BlocksFreeCount = 0;
- m_BlocksFreeSize = 0;
- m_IsFreeBitmap = 0;
- m_NullBlock->offset = 0;
- m_NullBlock->size = GetSize();
- Block* block = m_NullBlock->prevPhysical;
- m_NullBlock->prevPhysical = NULL;
- while (block)
- {
- Block* prev = block->prevPhysical;
- m_BlockAllocator.Free(block);
- block = prev;
- }
- memset(m_FreeList, 0, m_ListsCount * sizeof(Block*));
- memset(m_InnerIsFreeBitmap, 0, m_MemoryClasses * sizeof(UINT32));
- }
- AllocHandle BlockMetadata_TLSF::GetAllocationListBegin() const
- {
- if (m_AllocCount == 0)
- return (AllocHandle)0;
- for (Block* block = m_NullBlock->prevPhysical; block; block = block->prevPhysical)
- {
- if (!block->IsFree())
- return (AllocHandle)block;
- }
- D3D12MA_ASSERT(false && "If m_AllocCount > 0 then should find any allocation!");
- return (AllocHandle)0;
- }
- AllocHandle BlockMetadata_TLSF::GetNextAllocation(AllocHandle prevAlloc) const
- {
- Block* startBlock = (Block*)prevAlloc;
- D3D12MA_ASSERT(!startBlock->IsFree() && "Incorrect block!");
- for (Block* block = startBlock->prevPhysical; block; block = block->prevPhysical)
- {
- if (!block->IsFree())
- return (AllocHandle)block;
- }
- return (AllocHandle)0;
- }
- UINT64 BlockMetadata_TLSF::GetNextFreeRegionSize(AllocHandle alloc) const
- {
- Block* block = (Block*)alloc;
- D3D12MA_ASSERT(!block->IsFree() && "Incorrect block!");
- if (block->prevPhysical)
- return block->prevPhysical->IsFree() ? block->prevPhysical->size : 0;
- return 0;
- }
- void* BlockMetadata_TLSF::GetAllocationPrivateData(AllocHandle allocHandle) const
- {
- Block* block = (Block*)allocHandle;
- D3D12MA_ASSERT(!block->IsFree() && "Cannot get user data for free block!");
- return block->PrivateData();
- }
- void BlockMetadata_TLSF::SetAllocationPrivateData(AllocHandle allocHandle, void* privateData)
- {
- Block* block = (Block*)allocHandle;
- D3D12MA_ASSERT(!block->IsFree() && "Trying to set user data for not allocated block!");
- block->PrivateData() = privateData;
- }
- void BlockMetadata_TLSF::AddStatistics(Statistics& inoutStats) const
- {
- inoutStats.BlockCount++;
- inoutStats.AllocationCount += static_cast<UINT>(m_AllocCount);
- inoutStats.BlockBytes += GetSize();
- inoutStats.AllocationBytes += GetSize() - GetSumFreeSize();
- }
- void BlockMetadata_TLSF::AddDetailedStatistics(DetailedStatistics& inoutStats) const
- {
- inoutStats.Stats.BlockCount++;
- inoutStats.Stats.BlockBytes += GetSize();
- for (Block* block = m_NullBlock->prevPhysical; block != NULL; block = block->prevPhysical)
- {
- if (block->IsFree())
- AddDetailedStatisticsUnusedRange(inoutStats, block->size);
- else
- AddDetailedStatisticsAllocation(inoutStats, block->size);
- }
- if (m_NullBlock->size > 0)
- AddDetailedStatisticsUnusedRange(inoutStats, m_NullBlock->size);
- }
- void BlockMetadata_TLSF::WriteAllocationInfoToJson(JsonWriter& json) const
- {
- size_t blockCount = m_AllocCount + m_BlocksFreeCount;
- Vector<Block*> blockList(blockCount, *GetAllocs());
- size_t i = blockCount;
- if (m_NullBlock->size > 0)
- {
- ++blockCount;
- blockList.push_back(m_NullBlock);
- }
- for (Block* block = m_NullBlock->prevPhysical; block != NULL; block = block->prevPhysical)
- {
- blockList[--i] = block;
- }
- D3D12MA_ASSERT(i == 0);
- PrintDetailedMap_Begin(json, GetSumFreeSize(), GetAllocationCount(), m_BlocksFreeCount + static_cast<bool>(m_NullBlock->size));
- for (; i < blockCount; ++i)
- {
- Block* block = blockList[i];
- if (block->IsFree())
- PrintDetailedMap_UnusedRange(json, block->offset, block->size);
- else
- PrintDetailedMap_Allocation(json, block->offset, block->size, block->PrivateData());
- }
- PrintDetailedMap_End(json);
- }
- void BlockMetadata_TLSF::DebugLogAllAllocations() const
- {
- for (Block* block = m_NullBlock->prevPhysical; block != NULL; block = block->prevPhysical)
- {
- if (!block->IsFree())
- {
- DebugLogAllocation(block->offset, block->size, block->PrivateData());
- }
- }
- }
- UINT8 BlockMetadata_TLSF::SizeToMemoryClass(UINT64 size) const
- {
- if (size > SMALL_BUFFER_SIZE)
- return BitScanMSB(size) - MEMORY_CLASS_SHIFT;
- return 0;
- }
- UINT16 BlockMetadata_TLSF::SizeToSecondIndex(UINT64 size, UINT8 memoryClass) const
- {
- if (memoryClass == 0)
- {
- if (IsVirtual())
- return static_cast<UINT16>((size - 1) / 8);
- else
- return static_cast<UINT16>((size - 1) / 64);
- }
- return static_cast<UINT16>((size >> (memoryClass + MEMORY_CLASS_SHIFT - SECOND_LEVEL_INDEX)) ^ (1U << SECOND_LEVEL_INDEX));
- }
- UINT32 BlockMetadata_TLSF::GetListIndex(UINT8 memoryClass, UINT16 secondIndex) const
- {
- if (memoryClass == 0)
- return secondIndex;
- const UINT32 index = static_cast<UINT32>(memoryClass - 1) * (1 << SECOND_LEVEL_INDEX) + secondIndex;
- if (IsVirtual())
- return index + (1 << SECOND_LEVEL_INDEX);
- else
- return index + 4;
- }
- UINT32 BlockMetadata_TLSF::GetListIndex(UINT64 size) const
- {
- UINT8 memoryClass = SizeToMemoryClass(size);
- return GetListIndex(memoryClass, SizeToSecondIndex(size, memoryClass));
- }
- void BlockMetadata_TLSF::RemoveFreeBlock(Block* block)
- {
- D3D12MA_ASSERT(block != m_NullBlock);
- D3D12MA_ASSERT(block->IsFree());
- if (block->NextFree() != NULL)
- block->NextFree()->PrevFree() = block->PrevFree();
- if (block->PrevFree() != NULL)
- block->PrevFree()->NextFree() = block->NextFree();
- else
- {
- UINT8 memClass = SizeToMemoryClass(block->size);
- UINT16 secondIndex = SizeToSecondIndex(block->size, memClass);
- UINT32 index = GetListIndex(memClass, secondIndex);
- m_FreeList[index] = block->NextFree();
- if (block->NextFree() == NULL)
- {
- m_InnerIsFreeBitmap[memClass] &= ~(1U << secondIndex);
- if (m_InnerIsFreeBitmap[memClass] == 0)
- m_IsFreeBitmap &= ~(1UL << memClass);
- }
- }
- block->MarkTaken();
- block->PrivateData() = NULL;
- --m_BlocksFreeCount;
- m_BlocksFreeSize -= block->size;
- }
- void BlockMetadata_TLSF::InsertFreeBlock(Block* block)
- {
- D3D12MA_ASSERT(block != m_NullBlock);
- D3D12MA_ASSERT(!block->IsFree() && "Cannot insert block twice!");
- UINT8 memClass = SizeToMemoryClass(block->size);
- UINT16 secondIndex = SizeToSecondIndex(block->size, memClass);
- UINT32 index = GetListIndex(memClass, secondIndex);
- block->PrevFree() = NULL;
- block->NextFree() = m_FreeList[index];
- m_FreeList[index] = block;
- if (block->NextFree() != NULL)
- block->NextFree()->PrevFree() = block;
- else
- {
- m_InnerIsFreeBitmap[memClass] |= 1U << secondIndex;
- m_IsFreeBitmap |= 1UL << memClass;
- }
- ++m_BlocksFreeCount;
- m_BlocksFreeSize += block->size;
- }
- void BlockMetadata_TLSF::MergeBlock(Block* block, Block* prev)
- {
- D3D12MA_ASSERT(block->prevPhysical == prev && "Cannot merge seperate physical regions!");
- D3D12MA_ASSERT(!prev->IsFree() && "Cannot merge block that belongs to free list!");
- block->offset = prev->offset;
- block->size += prev->size;
- block->prevPhysical = prev->prevPhysical;
- if (block->prevPhysical)
- block->prevPhysical->nextPhysical = block;
- m_BlockAllocator.Free(prev);
- }
- BlockMetadata_TLSF::Block* BlockMetadata_TLSF::FindFreeBlock(UINT64 size, UINT32& listIndex) const
- {
- UINT8 memoryClass = SizeToMemoryClass(size);
- UINT32 innerFreeMap = m_InnerIsFreeBitmap[memoryClass] & (~0U << SizeToSecondIndex(size, memoryClass));
- if (!innerFreeMap)
- {
- // Check higher levels for avaiable blocks
- UINT32 freeMap = m_IsFreeBitmap & (~0UL << (memoryClass + 1));
- if (!freeMap)
- return NULL; // No more memory avaible
- // Find lowest free region
- memoryClass = BitScanLSB(freeMap);
- innerFreeMap = m_InnerIsFreeBitmap[memoryClass];
- D3D12MA_ASSERT(innerFreeMap != 0);
- }
- // Find lowest free subregion
- listIndex = GetListIndex(memoryClass, BitScanLSB(innerFreeMap));
- return m_FreeList[listIndex];
- }
- bool BlockMetadata_TLSF::CheckBlock(
- Block& block,
- UINT32 listIndex,
- UINT64 allocSize,
- UINT64 allocAlignment,
- AllocationRequest* pAllocationRequest)
- {
- D3D12MA_ASSERT(block.IsFree() && "Block is already taken!");
- UINT64 alignedOffset = AlignUp(block.offset, allocAlignment);
- if (block.size < allocSize + alignedOffset - block.offset)
- return false;
- // Alloc successful
- pAllocationRequest->allocHandle = (AllocHandle)█
- pAllocationRequest->size = allocSize - GetDebugMargin();
- pAllocationRequest->algorithmData = alignedOffset;
- // Place block at the start of list if it's normal block
- if (listIndex != m_ListsCount && block.PrevFree())
- {
- block.PrevFree()->NextFree() = block.NextFree();
- if (block.NextFree())
- block.NextFree()->PrevFree() = block.PrevFree();
- block.PrevFree() = NULL;
- block.NextFree() = m_FreeList[listIndex];
- m_FreeList[listIndex] = █
- if (block.NextFree())
- block.NextFree()->PrevFree() = █
- }
- return true;
- }
- #endif // _D3D12MA_BLOCK_METADATA_TLSF_FUNCTIONS
- #endif // _D3D12MA_BLOCK_METADATA_TLSF
- #ifndef _D3D12MA_MEMORY_BLOCK
- /*
- Represents a single block of device memory (heap).
- Base class for inheritance.
- Thread-safety: This class must be externally synchronized.
- */
- class MemoryBlock
- {
- public:
- // Creates the ID3D12Heap.
- MemoryBlock(
- AllocatorPimpl* allocator,
- const D3D12_HEAP_PROPERTIES& heapProps,
- D3D12_HEAP_FLAGS heapFlags,
- UINT64 size,
- UINT id);
- virtual ~MemoryBlock();
- const D3D12_HEAP_PROPERTIES& GetHeapProperties() const { return m_HeapProps; }
- D3D12_HEAP_FLAGS GetHeapFlags() const { return m_HeapFlags; }
- UINT64 GetSize() const { return m_Size; }
- UINT GetId() const { return m_Id; }
- ID3D12Heap* GetHeap() const { return m_Heap; }
- protected:
- AllocatorPimpl* const m_Allocator;
- const D3D12_HEAP_PROPERTIES m_HeapProps;
- const D3D12_HEAP_FLAGS m_HeapFlags;
- const UINT64 m_Size;
- const UINT m_Id;
- HRESULT Init(ID3D12ProtectedResourceSession* pProtectedSession, bool denyMsaaTextures);
- private:
- ID3D12Heap* m_Heap = NULL;
- D3D12MA_CLASS_NO_COPY(MemoryBlock)
- };
- #endif // _D3D12MA_MEMORY_BLOCK
- #ifndef _D3D12MA_NORMAL_BLOCK
- /*
- Represents a single block of device memory (heap) with all the data about its
- regions (aka suballocations, Allocation), assigned and free.
- Thread-safety: This class must be externally synchronized.
- */
- class NormalBlock : public MemoryBlock
- {
- public:
- BlockMetadata* m_pMetadata;
- NormalBlock(
- AllocatorPimpl* allocator,
- BlockVector* blockVector,
- const D3D12_HEAP_PROPERTIES& heapProps,
- D3D12_HEAP_FLAGS heapFlags,
- UINT64 size,
- UINT id);
- virtual ~NormalBlock();
- BlockVector* GetBlockVector() const { return m_BlockVector; }
- // 'algorithm' should be one of the *_ALGORITHM_* flags in enums POOL_FLAGS or VIRTUAL_BLOCK_FLAGS
- HRESULT Init(UINT32 algorithm, ID3D12ProtectedResourceSession* pProtectedSession, bool denyMsaaTextures);
- // Validates all data structures inside this object. If not valid, returns false.
- bool Validate() const;
- private:
- BlockVector* m_BlockVector;
- D3D12MA_CLASS_NO_COPY(NormalBlock)
- };
- #endif // _D3D12MA_NORMAL_BLOCK
- #ifndef _D3D12MA_COMMITTED_ALLOCATION_LIST_ITEM_TRAITS
- struct CommittedAllocationListItemTraits
- {
- using ItemType = Allocation;
- static ItemType* GetPrev(const ItemType* item)
- {
- D3D12MA_ASSERT(item->m_PackedData.GetType() == Allocation::TYPE_COMMITTED || item->m_PackedData.GetType() == Allocation::TYPE_HEAP);
- return item->m_Committed.prev;
- }
- static ItemType* GetNext(const ItemType* item)
- {
- D3D12MA_ASSERT(item->m_PackedData.GetType() == Allocation::TYPE_COMMITTED || item->m_PackedData.GetType() == Allocation::TYPE_HEAP);
- return item->m_Committed.next;
- }
- static ItemType*& AccessPrev(ItemType* item)
- {
- D3D12MA_ASSERT(item->m_PackedData.GetType() == Allocation::TYPE_COMMITTED || item->m_PackedData.GetType() == Allocation::TYPE_HEAP);
- return item->m_Committed.prev;
- }
- static ItemType*& AccessNext(ItemType* item)
- {
- D3D12MA_ASSERT(item->m_PackedData.GetType() == Allocation::TYPE_COMMITTED || item->m_PackedData.GetType() == Allocation::TYPE_HEAP);
- return item->m_Committed.next;
- }
- };
- #endif // _D3D12MA_COMMITTED_ALLOCATION_LIST_ITEM_TRAITS
- #ifndef _D3D12MA_COMMITTED_ALLOCATION_LIST
- /*
- Stores linked list of Allocation objects that are of TYPE_COMMITTED or TYPE_HEAP.
- Thread-safe, synchronized internally.
- */
- class CommittedAllocationList
- {
- public:
- CommittedAllocationList() = default;
- void Init(bool useMutex, D3D12_HEAP_TYPE heapType, PoolPimpl* pool);
- ~CommittedAllocationList();
- D3D12_HEAP_TYPE GetHeapType() const { return m_HeapType; }
- PoolPimpl* GetPool() const { return m_Pool; }
- UINT GetMemorySegmentGroup(AllocatorPimpl* allocator) const;
-
- void AddStatistics(Statistics& inoutStats);
- void AddDetailedStatistics(DetailedStatistics& inoutStats);
- // Writes JSON array with the list of allocations.
- void BuildStatsString(JsonWriter& json);
- void Register(Allocation* alloc);
- void Unregister(Allocation* alloc);
- private:
- using CommittedAllocationLinkedList = IntrusiveLinkedList<CommittedAllocationListItemTraits>;
- bool m_UseMutex = true;
- D3D12_HEAP_TYPE m_HeapType = D3D12_HEAP_TYPE_CUSTOM;
- PoolPimpl* m_Pool = NULL;
- D3D12MA_RW_MUTEX m_Mutex;
- CommittedAllocationLinkedList m_AllocationList;
- };
- #endif // _D3D12MA_COMMITTED_ALLOCATION_LIST
- #ifndef _D3D12M_COMMITTED_ALLOCATION_PARAMETERS
- struct CommittedAllocationParameters
- {
- CommittedAllocationList* m_List = NULL;
- D3D12_HEAP_PROPERTIES m_HeapProperties = {};
- D3D12_HEAP_FLAGS m_HeapFlags = D3D12_HEAP_FLAG_NONE;
- ID3D12ProtectedResourceSession* m_ProtectedSession = NULL;
- bool m_CanAlias = false;
- D3D12_RESIDENCY_PRIORITY m_ResidencyPriority = D3D12_RESIDENCY_PRIORITY_NONE;
- bool IsValid() const { return m_List != NULL; }
- };
- #endif // _D3D12M_COMMITTED_ALLOCATION_PARAMETERS
- // Simple variant data structure to hold all possible variations of ID3D12Device*::CreateCommittedResource* and ID3D12Device*::CreatePlacedResource* arguments
- struct CREATE_RESOURCE_PARAMS
- {
- CREATE_RESOURCE_PARAMS() = delete;
- CREATE_RESOURCE_PARAMS(
- const D3D12_RESOURCE_DESC* pResourceDesc,
- D3D12_RESOURCE_STATES InitialResourceState,
- const D3D12_CLEAR_VALUE* pOptimizedClearValue)
- : Variant(VARIANT_WITH_STATE)
- , pResourceDesc(pResourceDesc)
- , InitialResourceState(InitialResourceState)
- , pOptimizedClearValue(pOptimizedClearValue)
- {
- }
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- CREATE_RESOURCE_PARAMS(
- const D3D12_RESOURCE_DESC1* pResourceDesc,
- D3D12_RESOURCE_STATES InitialResourceState,
- const D3D12_CLEAR_VALUE* pOptimizedClearValue)
- : Variant(VARIANT_WITH_STATE_AND_DESC1)
- , pResourceDesc1(pResourceDesc)
- , InitialResourceState(InitialResourceState)
- , pOptimizedClearValue(pOptimizedClearValue)
- {
- }
- #endif
- #ifdef __ID3D12Device10_INTERFACE_DEFINED__
- CREATE_RESOURCE_PARAMS(
- const D3D12_RESOURCE_DESC1* pResourceDesc,
- D3D12_BARRIER_LAYOUT InitialLayout,
- const D3D12_CLEAR_VALUE* pOptimizedClearValue,
- UINT32 NumCastableFormats,
- DXGI_FORMAT* pCastableFormats)
- : Variant(VARIANT_WITH_LAYOUT)
- , pResourceDesc1(pResourceDesc)
- , InitialLayout(InitialLayout)
- , pOptimizedClearValue(pOptimizedClearValue)
- , NumCastableFormats(NumCastableFormats)
- , pCastableFormats(pCastableFormats)
- {
- }
- #endif
- enum VARIANT
- {
- VARIANT_INVALID = 0,
- VARIANT_WITH_STATE,
- VARIANT_WITH_STATE_AND_DESC1,
- VARIANT_WITH_LAYOUT
- };
- VARIANT Variant = VARIANT_INVALID;
- const D3D12_RESOURCE_DESC* GetResourceDesc() const
- {
- D3D12MA_ASSERT(Variant == VARIANT_WITH_STATE);
- return pResourceDesc;
- }
- const D3D12_RESOURCE_DESC*& AccessResourceDesc()
- {
- D3D12MA_ASSERT(Variant == VARIANT_WITH_STATE);
- return pResourceDesc;
- }
- const D3D12_RESOURCE_DESC* GetBaseResourceDesc() const
- {
- // D3D12_RESOURCE_DESC1 can be cast to D3D12_RESOURCE_DESC by discarding the new members at the end.
- return pResourceDesc;
- }
- D3D12_RESOURCE_STATES GetInitialResourceState() const
- {
- D3D12MA_ASSERT(Variant < VARIANT_WITH_LAYOUT);
- return InitialResourceState;
- }
- const D3D12_CLEAR_VALUE* GetOptimizedClearValue() const
- {
- return pOptimizedClearValue;
- }
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- const D3D12_RESOURCE_DESC1* GetResourceDesc1() const
- {
- D3D12MA_ASSERT(Variant >= VARIANT_WITH_STATE_AND_DESC1);
- return pResourceDesc1;
- }
- const D3D12_RESOURCE_DESC1*& AccessResourceDesc1()
- {
- D3D12MA_ASSERT(Variant >= VARIANT_WITH_STATE_AND_DESC1);
- return pResourceDesc1;
- }
- #endif
- #ifdef __ID3D12Device10_INTERFACE_DEFINED__
- D3D12_BARRIER_LAYOUT GetInitialLayout() const
- {
- D3D12MA_ASSERT(Variant >= VARIANT_WITH_LAYOUT);
- return InitialLayout;
- }
- UINT32 GetNumCastableFormats() const
- {
- D3D12MA_ASSERT(Variant >= VARIANT_WITH_LAYOUT);
- return NumCastableFormats;
- }
- DXGI_FORMAT* GetCastableFormats() const
- {
- D3D12MA_ASSERT(Variant >= VARIANT_WITH_LAYOUT);
- return pCastableFormats;
- }
- #endif
- private:
- union
- {
- const D3D12_RESOURCE_DESC* pResourceDesc;
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- const D3D12_RESOURCE_DESC1* pResourceDesc1;
- #endif
- };
- union
- {
- D3D12_RESOURCE_STATES InitialResourceState;
- #ifdef __ID3D12Device10_INTERFACE_DEFINED__
- D3D12_BARRIER_LAYOUT InitialLayout;
- #endif
- };
- const D3D12_CLEAR_VALUE* pOptimizedClearValue;
- #ifdef __ID3D12Device10_INTERFACE_DEFINED__
- UINT32 NumCastableFormats;
- DXGI_FORMAT* pCastableFormats;
- #endif
- };
- #ifndef _D3D12MA_BLOCK_VECTOR
- /*
- Sequence of NormalBlock. Represents memory blocks allocated for a specific
- heap type and possibly resource type (if only Tier 1 is supported).
- Synchronized internally with a mutex.
- */
- class BlockVector
- {
- friend class DefragmentationContextPimpl;
- D3D12MA_CLASS_NO_COPY(BlockVector)
- public:
- BlockVector(
- AllocatorPimpl* hAllocator,
- const D3D12_HEAP_PROPERTIES& heapProps,
- D3D12_HEAP_FLAGS heapFlags,
- UINT64 preferredBlockSize,
- size_t minBlockCount,
- size_t maxBlockCount,
- bool explicitBlockSize,
- UINT64 minAllocationAlignment,
- UINT32 algorithm,
- bool denyMsaaTextures,
- ID3D12ProtectedResourceSession* pProtectedSession,
- D3D12_RESIDENCY_PRIORITY residencyPriority);
- ~BlockVector();
- D3D12_RESIDENCY_PRIORITY GetResidencyPriority() const { return m_ResidencyPriority; }
- const D3D12_HEAP_PROPERTIES& GetHeapProperties() const { return m_HeapProps; }
- D3D12_HEAP_FLAGS GetHeapFlags() const { return m_HeapFlags; }
- UINT64 GetPreferredBlockSize() const { return m_PreferredBlockSize; }
- UINT32 GetAlgorithm() const { return m_Algorithm; }
- bool DeniesMsaaTextures() const { return m_DenyMsaaTextures; }
- // To be used only while the m_Mutex is locked. Used during defragmentation.
- size_t GetBlockCount() const { return m_Blocks.size(); }
- // To be used only while the m_Mutex is locked. Used during defragmentation.
- NormalBlock* GetBlock(size_t index) const { return m_Blocks[index]; }
- D3D12MA_RW_MUTEX& GetMutex() { return m_Mutex; }
- HRESULT CreateMinBlocks();
- bool IsEmpty();
- HRESULT Allocate(
- UINT64 size,
- UINT64 alignment,
- const ALLOCATION_DESC& allocDesc,
- size_t allocationCount,
- Allocation** pAllocations);
- void Free(Allocation* hAllocation);
- HRESULT CreateResource(
- UINT64 size,
- UINT64 alignment,
- const ALLOCATION_DESC& allocDesc,
- const CREATE_RESOURCE_PARAMS& createParams,
- Allocation** ppAllocation,
- REFIID riidResource,
- void** ppvResource);
- void AddStatistics(Statistics& inoutStats);
- void AddDetailedStatistics(DetailedStatistics& inoutStats);
- void WriteBlockInfoToJson(JsonWriter& json);
- private:
- AllocatorPimpl* const m_hAllocator;
- const D3D12_HEAP_PROPERTIES m_HeapProps;
- const D3D12_HEAP_FLAGS m_HeapFlags;
- const UINT64 m_PreferredBlockSize;
- const size_t m_MinBlockCount;
- const size_t m_MaxBlockCount;
- const bool m_ExplicitBlockSize;
- const UINT64 m_MinAllocationAlignment;
- const UINT32 m_Algorithm;
- const bool m_DenyMsaaTextures;
- ID3D12ProtectedResourceSession* const m_ProtectedSession;
- const D3D12_RESIDENCY_PRIORITY m_ResidencyPriority;
- /* There can be at most one allocation that is completely empty - a
- hysteresis to avoid pessimistic case of alternating creation and destruction
- of a ID3D12Heap. */
- bool m_HasEmptyBlock;
- D3D12MA_RW_MUTEX m_Mutex;
- // Incrementally sorted by sumFreeSize, ascending.
- Vector<NormalBlock*> m_Blocks;
- UINT m_NextBlockId;
- bool m_IncrementalSort = true;
- // Disable incremental sorting when freeing allocations
- void SetIncrementalSort(bool val) { m_IncrementalSort = val; }
- UINT64 CalcSumBlockSize() const;
- UINT64 CalcMaxBlockSize() const;
- // Finds and removes given block from vector.
- void Remove(NormalBlock* pBlock);
- // Performs single step in sorting m_Blocks. They may not be fully sorted
- // after this call.
- void IncrementallySortBlocks();
- void SortByFreeSize();
- HRESULT AllocatePage(
- UINT64 size,
- UINT64 alignment,
- const ALLOCATION_DESC& allocDesc,
- Allocation** pAllocation);
- HRESULT AllocateFromBlock(
- NormalBlock* pBlock,
- UINT64 size,
- UINT64 alignment,
- ALLOCATION_FLAGS allocFlags,
- void* pPrivateData,
- UINT32 strategy,
- Allocation** pAllocation);
- HRESULT CommitAllocationRequest(
- AllocationRequest& allocRequest,
- NormalBlock* pBlock,
- UINT64 size,
- UINT64 alignment,
- void* pPrivateData,
- Allocation** pAllocation);
- HRESULT CreateBlock(
- UINT64 blockSize,
- size_t* pNewBlockIndex);
- };
- #endif // _D3D12MA_BLOCK_VECTOR
- #ifndef _D3D12MA_CURRENT_BUDGET_DATA
- class CurrentBudgetData
- {
- public:
- bool ShouldUpdateBudget() const { return m_OperationsSinceBudgetFetch >= 30; }
- void GetStatistics(Statistics& outStats, UINT group) const;
- void GetBudget(bool useMutex,
- UINT64* outLocalUsage, UINT64* outLocalBudget,
- UINT64* outNonLocalUsage, UINT64* outNonLocalBudget);
- #if D3D12MA_DXGI_1_4
- HRESULT UpdateBudget(IDXGIAdapter3* adapter3, bool useMutex);
- #endif
- void AddAllocation(UINT group, UINT64 allocationBytes);
- void RemoveAllocation(UINT group, UINT64 allocationBytes);
- void AddBlock(UINT group, UINT64 blockBytes);
- void RemoveBlock(UINT group, UINT64 blockBytes);
- private:
- D3D12MA_ATOMIC_UINT32 m_BlockCount[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
- D3D12MA_ATOMIC_UINT32 m_AllocationCount[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
- D3D12MA_ATOMIC_UINT64 m_BlockBytes[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
- D3D12MA_ATOMIC_UINT64 m_AllocationBytes[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
- D3D12MA_ATOMIC_UINT32 m_OperationsSinceBudgetFetch = {0};
- D3D12MA_RW_MUTEX m_BudgetMutex;
- UINT64 m_D3D12Usage[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
- UINT64 m_D3D12Budget[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
- UINT64 m_BlockBytesAtD3D12Fetch[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
- };
- #ifndef _D3D12MA_CURRENT_BUDGET_DATA_FUNCTIONS
- void CurrentBudgetData::GetStatistics(Statistics& outStats, UINT group) const
- {
- outStats.BlockCount = m_BlockCount[group];
- outStats.AllocationCount = m_AllocationCount[group];
- outStats.BlockBytes = m_BlockBytes[group];
- outStats.AllocationBytes = m_AllocationBytes[group];
- }
- void CurrentBudgetData::GetBudget(bool useMutex,
- UINT64* outLocalUsage, UINT64* outLocalBudget,
- UINT64* outNonLocalUsage, UINT64* outNonLocalBudget)
- {
- MutexLockRead lockRead(m_BudgetMutex, useMutex);
- if (outLocalUsage)
- {
- const UINT64 D3D12Usage = m_D3D12Usage[DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY];
- const UINT64 blockBytes = m_BlockBytes[DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY];
- const UINT64 blockBytesAtD3D12Fetch = m_BlockBytesAtD3D12Fetch[DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY];
- *outLocalUsage = D3D12Usage + blockBytes > blockBytesAtD3D12Fetch ?
- D3D12Usage + blockBytes - blockBytesAtD3D12Fetch : 0;
- }
- if (outLocalBudget)
- *outLocalBudget = m_D3D12Budget[DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY];
- if (outNonLocalUsage)
- {
- const UINT64 D3D12Usage = m_D3D12Usage[DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY];
- const UINT64 blockBytes = m_BlockBytes[DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY];
- const UINT64 blockBytesAtD3D12Fetch = m_BlockBytesAtD3D12Fetch[DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY];
- *outNonLocalUsage = D3D12Usage + blockBytes > blockBytesAtD3D12Fetch ?
- D3D12Usage + blockBytes - blockBytesAtD3D12Fetch : 0;
- }
- if (outNonLocalBudget)
- *outNonLocalBudget = m_D3D12Budget[DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY];
- }
- #if D3D12MA_DXGI_1_4
- HRESULT CurrentBudgetData::UpdateBudget(IDXGIAdapter3* adapter3, bool useMutex)
- {
- D3D12MA_ASSERT(adapter3);
- DXGI_QUERY_VIDEO_MEMORY_INFO infoLocal = {};
- DXGI_QUERY_VIDEO_MEMORY_INFO infoNonLocal = {};
- const HRESULT hrLocal = adapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &infoLocal);
- const HRESULT hrNonLocal = adapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &infoNonLocal);
- if (SUCCEEDED(hrLocal) || SUCCEEDED(hrNonLocal))
- {
- MutexLockWrite lockWrite(m_BudgetMutex, useMutex);
- if (SUCCEEDED(hrLocal))
- {
- m_D3D12Usage[0] = infoLocal.CurrentUsage;
- m_D3D12Budget[0] = infoLocal.Budget;
- }
- if (SUCCEEDED(hrNonLocal))
- {
- m_D3D12Usage[1] = infoNonLocal.CurrentUsage;
- m_D3D12Budget[1] = infoNonLocal.Budget;
- }
- m_BlockBytesAtD3D12Fetch[0] = m_BlockBytes[0];
- m_BlockBytesAtD3D12Fetch[1] = m_BlockBytes[1];
- m_OperationsSinceBudgetFetch = 0;
- }
- return FAILED(hrLocal) ? hrLocal : hrNonLocal;
- }
- #endif // #if D3D12MA_DXGI_1_4
- void CurrentBudgetData::AddAllocation(UINT group, UINT64 allocationBytes)
- {
- ++m_AllocationCount[group];
- m_AllocationBytes[group] += allocationBytes;
- ++m_OperationsSinceBudgetFetch;
- }
- void CurrentBudgetData::RemoveAllocation(UINT group, UINT64 allocationBytes)
- {
- D3D12MA_ASSERT(m_AllocationBytes[group] >= allocationBytes);
- D3D12MA_ASSERT(m_AllocationCount[group] > 0);
- m_AllocationBytes[group] -= allocationBytes;
- --m_AllocationCount[group];
- ++m_OperationsSinceBudgetFetch;
- }
- void CurrentBudgetData::AddBlock(UINT group, UINT64 blockBytes)
- {
- ++m_BlockCount[group];
- m_BlockBytes[group] += blockBytes;
- ++m_OperationsSinceBudgetFetch;
- }
- void CurrentBudgetData::RemoveBlock(UINT group, UINT64 blockBytes)
- {
- D3D12MA_ASSERT(m_BlockBytes[group] >= blockBytes);
- D3D12MA_ASSERT(m_BlockCount[group] > 0);
- m_BlockBytes[group] -= blockBytes;
- --m_BlockCount[group];
- ++m_OperationsSinceBudgetFetch;
- }
- #endif // _D3D12MA_CURRENT_BUDGET_DATA_FUNCTIONS
- #endif // _D3D12MA_CURRENT_BUDGET_DATA
- #ifndef _D3D12MA_DEFRAGMENTATION_CONTEXT_PIMPL
- class DefragmentationContextPimpl
- {
- D3D12MA_CLASS_NO_COPY(DefragmentationContextPimpl)
- public:
- DefragmentationContextPimpl(
- AllocatorPimpl* hAllocator,
- const DEFRAGMENTATION_DESC& desc,
- BlockVector* poolVector);
- ~DefragmentationContextPimpl();
- void GetStats(DEFRAGMENTATION_STATS& outStats) { outStats = m_GlobalStats; }
- const ALLOCATION_CALLBACKS& GetAllocs() const { return m_Moves.GetAllocs(); }
- HRESULT DefragmentPassBegin(DEFRAGMENTATION_PASS_MOVE_INFO& moveInfo);
- HRESULT DefragmentPassEnd(DEFRAGMENTATION_PASS_MOVE_INFO& moveInfo);
- private:
- // Max number of allocations to ignore due to size constraints before ending single pass
- static const UINT8 MAX_ALLOCS_TO_IGNORE = 16;
- enum class CounterStatus { Pass, Ignore, End };
- struct FragmentedBlock
- {
- UINT32 data;
- NormalBlock* block;
- };
- struct StateBalanced
- {
- UINT64 avgFreeSize = 0;
- UINT64 avgAllocSize = UINT64_MAX;
- };
- struct MoveAllocationData
- {
- UINT64 size;
- UINT64 alignment;
- ALLOCATION_FLAGS flags;
- DEFRAGMENTATION_MOVE move = {};
- };
- const UINT64 m_MaxPassBytes;
- const UINT32 m_MaxPassAllocations;
- Vector<DEFRAGMENTATION_MOVE> m_Moves;
- UINT8 m_IgnoredAllocs = 0;
- UINT32 m_Algorithm;
- UINT32 m_BlockVectorCount;
- BlockVector* m_PoolBlockVector;
- BlockVector** m_pBlockVectors;
- size_t m_ImmovableBlockCount = 0;
- DEFRAGMENTATION_STATS m_GlobalStats = { 0 };
- DEFRAGMENTATION_STATS m_PassStats = { 0 };
- void* m_AlgorithmState = NULL;
- static MoveAllocationData GetMoveData(AllocHandle handle, BlockMetadata* metadata);
- CounterStatus CheckCounters(UINT64 bytes);
- bool IncrementCounters(UINT64 bytes);
- bool ReallocWithinBlock(BlockVector& vector, NormalBlock* block);
- bool AllocInOtherBlock(size_t start, size_t end, MoveAllocationData& data, BlockVector& vector);
- bool ComputeDefragmentation(BlockVector& vector, size_t index);
- bool ComputeDefragmentation_Fast(BlockVector& vector);
- bool ComputeDefragmentation_Balanced(BlockVector& vector, size_t index, bool update);
- bool ComputeDefragmentation_Full(BlockVector& vector);
- void UpdateVectorStatistics(BlockVector& vector, StateBalanced& state);
- };
- #endif // _D3D12MA_DEFRAGMENTATION_CONTEXT_PIMPL
- #ifndef _D3D12MA_POOL_PIMPL
- class PoolPimpl
- {
- friend class Allocator;
- friend struct PoolListItemTraits;
- public:
- PoolPimpl(AllocatorPimpl* allocator, const POOL_DESC& desc);
- ~PoolPimpl();
- AllocatorPimpl* GetAllocator() const { return m_Allocator; }
- const POOL_DESC& GetDesc() const { return m_Desc; }
- bool SupportsCommittedAllocations() const { return m_Desc.BlockSize == 0; }
- LPCWSTR GetName() const { return m_Name; }
- BlockVector* GetBlockVector() { return m_BlockVector; }
- CommittedAllocationList* GetCommittedAllocationList() { return SupportsCommittedAllocations() ? &m_CommittedAllocations : NULL; }
- HRESULT Init();
- void GetStatistics(Statistics& outStats);
- void CalculateStatistics(DetailedStatistics& outStats);
- void AddDetailedStatistics(DetailedStatistics& inoutStats);
- void SetName(LPCWSTR Name);
- private:
- AllocatorPimpl* m_Allocator; // Externally owned object.
- POOL_DESC m_Desc;
- BlockVector* m_BlockVector; // Owned object.
- CommittedAllocationList m_CommittedAllocations;
- wchar_t* m_Name;
- PoolPimpl* m_PrevPool = NULL;
- PoolPimpl* m_NextPool = NULL;
- void FreeName();
- };
- struct PoolListItemTraits
- {
- using ItemType = PoolPimpl;
- static ItemType* GetPrev(const ItemType* item) { return item->m_PrevPool; }
- static ItemType* GetNext(const ItemType* item) { return item->m_NextPool; }
- static ItemType*& AccessPrev(ItemType* item) { return item->m_PrevPool; }
- static ItemType*& AccessNext(ItemType* item) { return item->m_NextPool; }
- };
- #endif // _D3D12MA_POOL_PIMPL
- #ifndef _D3D12MA_ALLOCATOR_PIMPL
- class AllocatorPimpl
- {
- friend class Allocator;
- friend class Pool;
- public:
- std::atomic_uint32_t m_RefCount = {1};
- CurrentBudgetData m_Budget;
- AllocatorPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks, const ALLOCATOR_DESC& desc);
- ~AllocatorPimpl();
- ID3D12Device* GetDevice() const { return m_Device; }
- #ifdef __ID3D12Device1_INTERFACE_DEFINED__
- ID3D12Device1* GetDevice1() const { return m_Device1; }
- #endif
- #ifdef __ID3D12Device4_INTERFACE_DEFINED__
- ID3D12Device4* GetDevice4() const { return m_Device4; }
- #endif
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- ID3D12Device8* GetDevice8() const { return m_Device8; }
- #endif
- // Shortcut for "Allocation Callbacks", because this function is called so often.
- const ALLOCATION_CALLBACKS& GetAllocs() const { return m_AllocationCallbacks; }
- const D3D12_FEATURE_DATA_D3D12_OPTIONS& GetD3D12Options() const { return m_D3D12Options; }
- BOOL IsUMA() const { return m_D3D12Architecture.UMA; }
- BOOL IsCacheCoherentUMA() const { return m_D3D12Architecture.CacheCoherentUMA; }
- bool SupportsResourceHeapTier2() const { return m_D3D12Options.ResourceHeapTier >= D3D12_RESOURCE_HEAP_TIER_2; }
- bool UseMutex() const { return m_UseMutex; }
- AllocationObjectAllocator& GetAllocationObjectAllocator() { return m_AllocationObjectAllocator; }
- UINT GetCurrentFrameIndex() const { return m_CurrentFrameIndex.load(); }
- /*
- If SupportsResourceHeapTier2():
- 0: D3D12_HEAP_TYPE_DEFAULT
- 1: D3D12_HEAP_TYPE_UPLOAD
- 2: D3D12_HEAP_TYPE_READBACK
- else:
- 0: D3D12_HEAP_TYPE_DEFAULT + buffer
- 1: D3D12_HEAP_TYPE_DEFAULT + texture
- 2: D3D12_HEAP_TYPE_DEFAULT + texture RT or DS
- 3: D3D12_HEAP_TYPE_UPLOAD + buffer
- 4: D3D12_HEAP_TYPE_UPLOAD + texture
- 5: D3D12_HEAP_TYPE_UPLOAD + texture RT or DS
- 6: D3D12_HEAP_TYPE_READBACK + buffer
- 7: D3D12_HEAP_TYPE_READBACK + texture
- 8: D3D12_HEAP_TYPE_READBACK + texture RT or DS
- */
- UINT GetDefaultPoolCount() const { return SupportsResourceHeapTier2() ? 3 : 9; }
- BlockVector** GetDefaultPools() { return m_BlockVectors; }
- HRESULT Init(const ALLOCATOR_DESC& desc);
- bool HeapFlagsFulfillResourceHeapTier(D3D12_HEAP_FLAGS flags) const;
- UINT StandardHeapTypeToMemorySegmentGroup(D3D12_HEAP_TYPE heapType) const;
- UINT HeapPropertiesToMemorySegmentGroup(const D3D12_HEAP_PROPERTIES& heapProps) const;
- UINT64 GetMemoryCapacity(UINT memorySegmentGroup) const;
- HRESULT CreatePlacedResourceWrap(
- ID3D12Heap *pHeap,
- UINT64 HeapOffset,
- const CREATE_RESOURCE_PARAMS& createParams,
- REFIID riidResource,
- void** ppvResource);
- HRESULT CreateResource(
- const ALLOCATION_DESC* pAllocDesc,
- const CREATE_RESOURCE_PARAMS& createParams,
- Allocation** ppAllocation,
- REFIID riidResource,
- void** ppvResource);
- HRESULT CreateAliasingResource(
- Allocation* pAllocation,
- UINT64 AllocationLocalOffset,
- const CREATE_RESOURCE_PARAMS& createParams,
- REFIID riidResource,
- void** ppvResource);
- HRESULT AllocateMemory(
- const ALLOCATION_DESC* pAllocDesc,
- const D3D12_RESOURCE_ALLOCATION_INFO* pAllocInfo,
- Allocation** ppAllocation);
- // Unregisters allocation from the collection of dedicated allocations.
- // Allocation object must be deleted externally afterwards.
- void FreeCommittedMemory(Allocation* allocation);
- // Unregisters allocation from the collection of placed allocations.
- // Allocation object must be deleted externally afterwards.
- void FreePlacedMemory(Allocation* allocation);
- // Unregisters allocation from the collection of dedicated allocations and destroys associated heap.
- // Allocation object must be deleted externally afterwards.
- void FreeHeapMemory(Allocation* allocation);
- void SetResidencyPriority(ID3D12Pageable* obj, D3D12_RESIDENCY_PRIORITY priority) const;
- void SetCurrentFrameIndex(UINT frameIndex);
- // For more deailed stats use outCutomHeaps to access statistics divided into L0 and L1 group
- void CalculateStatistics(TotalStatistics& outStats, DetailedStatistics outCutomHeaps[2] = NULL);
- void GetBudget(Budget* outLocalBudget, Budget* outNonLocalBudget);
- void GetBudgetForHeapType(Budget& outBudget, D3D12_HEAP_TYPE heapType);
- void BuildStatsString(WCHAR** ppStatsString, BOOL detailedMap);
- void FreeStatsString(WCHAR* pStatsString);
- private:
- using PoolList = IntrusiveLinkedList<PoolListItemTraits>;
- const bool m_UseMutex;
- const bool m_AlwaysCommitted;
- const bool m_MsaaAlwaysCommitted;
- bool m_DefaultPoolsNotZeroed = false;
- ID3D12Device* m_Device; // AddRef
- #ifdef __ID3D12Device1_INTERFACE_DEFINED__
- ID3D12Device1* m_Device1 = NULL; // AddRef, optional
- #endif
- #ifdef __ID3D12Device4_INTERFACE_DEFINED__
- ID3D12Device4* m_Device4 = NULL; // AddRef, optional
- #endif
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- ID3D12Device8* m_Device8 = NULL; // AddRef, optional
- #endif
- #ifdef __ID3D12Device10_INTERFACE_DEFINED__
- ID3D12Device10* m_Device10 = NULL; // AddRef, optional
- #endif
- IDXGIAdapter* m_Adapter; // AddRef
- #if D3D12MA_DXGI_1_4
- IDXGIAdapter3* m_Adapter3 = NULL; // AddRef, optional
- #endif
- UINT64 m_PreferredBlockSize;
- ALLOCATION_CALLBACKS m_AllocationCallbacks;
- D3D12MA_ATOMIC_UINT32 m_CurrentFrameIndex;
- DXGI_ADAPTER_DESC m_AdapterDesc;
- D3D12_FEATURE_DATA_D3D12_OPTIONS m_D3D12Options;
- D3D12_FEATURE_DATA_ARCHITECTURE m_D3D12Architecture;
- AllocationObjectAllocator m_AllocationObjectAllocator;
- D3D12MA_RW_MUTEX m_PoolsMutex[HEAP_TYPE_COUNT];
- PoolList m_Pools[HEAP_TYPE_COUNT];
- // Default pools.
- BlockVector* m_BlockVectors[DEFAULT_POOL_MAX_COUNT];
- CommittedAllocationList m_CommittedAllocations[STANDARD_HEAP_TYPE_COUNT];
- /*
- Heuristics that decides whether a resource should better be placed in its own,
- dedicated allocation (committed resource rather than placed resource).
- */
- template<typename D3D12_RESOURCE_DESC_T>
- static bool PrefersCommittedAllocation(const D3D12_RESOURCE_DESC_T& resourceDesc);
- // Allocates and registers new committed resource with implicit heap, as dedicated allocation.
- // Creates and returns Allocation object and optionally D3D12 resource.
- HRESULT AllocateCommittedResource(
- const CommittedAllocationParameters& committedAllocParams,
- UINT64 resourceSize, bool withinBudget, void* pPrivateData,
- const CREATE_RESOURCE_PARAMS& createParams,
- Allocation** ppAllocation, REFIID riidResource, void** ppvResource);
- // Allocates and registers new heap without any resources placed in it, as dedicated allocation.
- // Creates and returns Allocation object.
- HRESULT AllocateHeap(
- const CommittedAllocationParameters& committedAllocParams,
- const D3D12_RESOURCE_ALLOCATION_INFO& allocInfo, bool withinBudget,
- void* pPrivateData, Allocation** ppAllocation);
- template<typename D3D12_RESOURCE_DESC_T>
- HRESULT CalcAllocationParams(const ALLOCATION_DESC& allocDesc, UINT64 allocSize,
- const D3D12_RESOURCE_DESC_T* resDesc, // Optional
- BlockVector*& outBlockVector, CommittedAllocationParameters& outCommittedAllocationParams, bool& outPreferCommitted);
- // Returns UINT32_MAX if index cannot be calculcated.
- UINT CalcDefaultPoolIndex(const ALLOCATION_DESC& allocDesc, ResourceClass resourceClass) const;
- void CalcDefaultPoolParams(D3D12_HEAP_TYPE& outHeapType, D3D12_HEAP_FLAGS& outHeapFlags, UINT index) const;
- // Registers Pool object in m_Pools.
- void RegisterPool(Pool* pool, D3D12_HEAP_TYPE heapType);
- // Unregisters Pool object from m_Pools.
- void UnregisterPool(Pool* pool, D3D12_HEAP_TYPE heapType);
- HRESULT UpdateD3D12Budget();
-
- D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfoNative(const D3D12_RESOURCE_DESC& resourceDesc) const;
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfoNative(const D3D12_RESOURCE_DESC1& resourceDesc) const;
- #endif
- template<typename D3D12_RESOURCE_DESC_T>
- D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfo(D3D12_RESOURCE_DESC_T& inOutResourceDesc) const;
- bool NewAllocationWithinBudget(D3D12_HEAP_TYPE heapType, UINT64 size);
- // Writes object { } with data of given budget.
- static void WriteBudgetToJson(JsonWriter& json, const Budget& budget);
- };
- #ifndef _D3D12MA_ALLOCATOR_PIMPL_FUNCTINOS
- AllocatorPimpl::AllocatorPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks, const ALLOCATOR_DESC& desc)
- : m_UseMutex((desc.Flags & ALLOCATOR_FLAG_SINGLETHREADED) == 0),
- m_AlwaysCommitted((desc.Flags & ALLOCATOR_FLAG_ALWAYS_COMMITTED) != 0),
- m_MsaaAlwaysCommitted((desc.Flags & ALLOCATOR_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED) != 0),
- m_Device(desc.pDevice),
- m_Adapter(desc.pAdapter),
- m_PreferredBlockSize(desc.PreferredBlockSize != 0 ? desc.PreferredBlockSize : D3D12MA_DEFAULT_BLOCK_SIZE),
- m_AllocationCallbacks(allocationCallbacks),
- m_CurrentFrameIndex(0),
- // Below this line don't use allocationCallbacks but m_AllocationCallbacks!!!
- m_AllocationObjectAllocator(m_AllocationCallbacks)
- {
- // desc.pAllocationCallbacks intentionally ignored here, preprocessed by CreateAllocator.
- ZeroMemory(&m_D3D12Options, sizeof(m_D3D12Options));
- ZeroMemory(&m_D3D12Architecture, sizeof(m_D3D12Architecture));
- ZeroMemory(m_BlockVectors, sizeof(m_BlockVectors));
- for (UINT i = 0; i < STANDARD_HEAP_TYPE_COUNT; ++i)
- {
- m_CommittedAllocations[i].Init(
- m_UseMutex,
- (D3D12_HEAP_TYPE)(D3D12_HEAP_TYPE_DEFAULT + i),
- NULL); // pool
- }
- m_Device->AddRef();
- m_Adapter->AddRef();
- }
- HRESULT AllocatorPimpl::Init(const ALLOCATOR_DESC& desc)
- {
- #if D3D12MA_DXGI_1_4
- desc.pAdapter->QueryInterface(D3D12MA_IID_PPV_ARGS(&m_Adapter3));
- #endif
- #ifdef __ID3D12Device1_INTERFACE_DEFINED__
- m_Device->QueryInterface(D3D12MA_IID_PPV_ARGS(&m_Device1));
- #endif
- #ifdef __ID3D12Device4_INTERFACE_DEFINED__
- m_Device->QueryInterface(D3D12MA_IID_PPV_ARGS(&m_Device4));
- #endif
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- m_Device->QueryInterface(D3D12MA_IID_PPV_ARGS(&m_Device8));
-
- if((desc.Flags & ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED) != 0)
- {
- D3D12_FEATURE_DATA_D3D12_OPTIONS7 options7 = {};
- if(SUCCEEDED(m_Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &options7, sizeof(options7))))
- {
- // DEFAULT_POOLS_NOT_ZEROED both supported and enabled by the user.
- m_DefaultPoolsNotZeroed = true;
- }
- }
- #endif
- #ifdef __ID3D12Device10_INTERFACE_DEFINED__
- m_Device->QueryInterface(D3D12MA_IID_PPV_ARGS(&m_Device10));
- #endif
- HRESULT hr = m_Adapter->GetDesc(&m_AdapterDesc);
- if (FAILED(hr))
- {
- return hr;
- }
- hr = m_Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &m_D3D12Options, sizeof(m_D3D12Options));
- if (FAILED(hr))
- {
- return hr;
- }
- #ifdef D3D12MA_FORCE_RESOURCE_HEAP_TIER
- m_D3D12Options.ResourceHeapTier = (D3D12MA_FORCE_RESOURCE_HEAP_TIER);
- #endif
- hr = m_Device->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE, &m_D3D12Architecture, sizeof(m_D3D12Architecture));
- if (FAILED(hr))
- {
- m_D3D12Architecture.UMA = FALSE;
- m_D3D12Architecture.CacheCoherentUMA = FALSE;
- }
- D3D12_HEAP_PROPERTIES heapProps = {};
- const UINT defaultPoolCount = GetDefaultPoolCount();
- for (UINT i = 0; i < defaultPoolCount; ++i)
- {
- D3D12_HEAP_FLAGS heapFlags;
- CalcDefaultPoolParams(heapProps.Type, heapFlags, i);
- #if D3D12MA_CREATE_NOT_ZEROED_AVAILABLE
- if(m_DefaultPoolsNotZeroed)
- {
- heapFlags |= D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;
- }
- #endif
- m_BlockVectors[i] = D3D12MA_NEW(GetAllocs(), BlockVector)(
- this, // hAllocator
- heapProps, // heapType
- heapFlags, // heapFlags
- m_PreferredBlockSize,
- 0, // minBlockCount
- SIZE_MAX, // maxBlockCount
- false, // explicitBlockSize
- D3D12MA_DEBUG_ALIGNMENT, // minAllocationAlignment
- 0, // Default algorithm,
- m_MsaaAlwaysCommitted,
- NULL, // pProtectedSession
- D3D12_RESIDENCY_PRIORITY_NONE); // residencyPriority
- // No need to call m_pBlockVectors[i]->CreateMinBlocks here, becase minBlockCount is 0.
- }
- #if D3D12MA_DXGI_1_4
- UpdateD3D12Budget();
- #endif
- return S_OK;
- }
- AllocatorPimpl::~AllocatorPimpl()
- {
- #ifdef __ID3D12Device10_INTERFACE_DEFINED__
- SAFE_RELEASE(m_Device10);
- #endif
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- SAFE_RELEASE(m_Device8);
- #endif
- #ifdef __ID3D12Device4_INTERFACE_DEFINED__
- SAFE_RELEASE(m_Device4);
- #endif
- #ifdef __ID3D12Device1_INTERFACE_DEFINED__
- SAFE_RELEASE(m_Device1);
- #endif
- #if D3D12MA_DXGI_1_4
- SAFE_RELEASE(m_Adapter3);
- #endif
- SAFE_RELEASE(m_Adapter);
- SAFE_RELEASE(m_Device);
- for (UINT i = DEFAULT_POOL_MAX_COUNT; i--; )
- {
- D3D12MA_DELETE(GetAllocs(), m_BlockVectors[i]);
- }
- for (UINT i = HEAP_TYPE_COUNT; i--; )
- {
- if (!m_Pools[i].IsEmpty())
- {
- D3D12MA_ASSERT(0 && "Unfreed pools found!");
- }
- }
- }
- bool AllocatorPimpl::HeapFlagsFulfillResourceHeapTier(D3D12_HEAP_FLAGS flags) const
- {
- if (SupportsResourceHeapTier2())
- {
- return true;
- }
- else
- {
- const bool allowBuffers = (flags & D3D12_HEAP_FLAG_DENY_BUFFERS) == 0;
- const bool allowRtDsTextures = (flags & D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES) == 0;
- const bool allowNonRtDsTextures = (flags & D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES) == 0;
- const uint8_t allowedGroupCount = (allowBuffers ? 1 : 0) + (allowRtDsTextures ? 1 : 0) + (allowNonRtDsTextures ? 1 : 0);
- return allowedGroupCount == 1;
- }
- }
- UINT AllocatorPimpl::StandardHeapTypeToMemorySegmentGroup(D3D12_HEAP_TYPE heapType) const
- {
- D3D12MA_ASSERT(IsHeapTypeStandard(heapType));
- if (IsUMA())
- return DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY;
- return heapType == D3D12_HEAP_TYPE_DEFAULT ?
- DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY : DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY;
- }
- UINT AllocatorPimpl::HeapPropertiesToMemorySegmentGroup(const D3D12_HEAP_PROPERTIES& heapProps) const
- {
- if (IsUMA())
- return DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY;
- if (heapProps.MemoryPoolPreference == D3D12_MEMORY_POOL_UNKNOWN)
- return StandardHeapTypeToMemorySegmentGroup(heapProps.Type);
- return heapProps.MemoryPoolPreference == D3D12_MEMORY_POOL_L1 ?
- DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY : DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY;
- }
- UINT64 AllocatorPimpl::GetMemoryCapacity(UINT memorySegmentGroup) const
- {
- switch (memorySegmentGroup)
- {
- case DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY:
- return IsUMA() ?
- m_AdapterDesc.DedicatedVideoMemory + m_AdapterDesc.SharedSystemMemory : m_AdapterDesc.DedicatedVideoMemory;
- case DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY:
- return IsUMA() ? 0 : m_AdapterDesc.SharedSystemMemory;
- default:
- D3D12MA_ASSERT(0);
- return UINT64_MAX;
- }
- }
- HRESULT AllocatorPimpl::CreatePlacedResourceWrap(
- ID3D12Heap *pHeap,
- UINT64 HeapOffset,
- const CREATE_RESOURCE_PARAMS& createParams,
- REFIID riidResource,
- void** ppvResource)
- {
- #ifdef __ID3D12Device10_INTERFACE_DEFINED__
- if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_LAYOUT)
- {
- if (!m_Device10)
- {
- return E_NOINTERFACE;
- }
- return m_Device10->CreatePlacedResource2(pHeap, HeapOffset,
- createParams.GetResourceDesc1(), createParams.GetInitialLayout(),
- createParams.GetOptimizedClearValue(), createParams.GetNumCastableFormats(),
- createParams.GetCastableFormats(), riidResource, ppvResource);
- } else
- #endif
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1)
- {
- if (!m_Device8)
- {
- return E_NOINTERFACE;
- }
- return m_Device8->CreatePlacedResource1(pHeap, HeapOffset,
- createParams.GetResourceDesc1(), createParams.GetInitialResourceState(),
- createParams.GetOptimizedClearValue(), riidResource, ppvResource);
- } else
- #endif
- if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE)
- {
- return m_Device->CreatePlacedResource(pHeap, HeapOffset,
- createParams.GetResourceDesc(), createParams.GetInitialResourceState(),
- createParams.GetOptimizedClearValue(), riidResource, ppvResource);
- }
- else
- {
- D3D12MA_ASSERT(0);
- return E_INVALIDARG;
- }
- }
- HRESULT AllocatorPimpl::CreateResource(
- const ALLOCATION_DESC* pAllocDesc,
- const CREATE_RESOURCE_PARAMS& createParams,
- Allocation** ppAllocation,
- REFIID riidResource,
- void** ppvResource)
- {
- D3D12MA_ASSERT(pAllocDesc && createParams.GetBaseResourceDesc() && ppAllocation);
- *ppAllocation = NULL;
- if (ppvResource)
- {
- *ppvResource = NULL;
- }
- CREATE_RESOURCE_PARAMS finalCreateParams = createParams;
- D3D12_RESOURCE_DESC finalResourceDesc;
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- D3D12_RESOURCE_DESC1 finalResourceDesc1;
- #endif
- D3D12_RESOURCE_ALLOCATION_INFO resAllocInfo;
- if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE)
- {
- finalResourceDesc = *createParams.GetResourceDesc();
- finalCreateParams.AccessResourceDesc() = &finalResourceDesc;
- resAllocInfo = GetResourceAllocationInfo(finalResourceDesc);
- }
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- else if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1)
- {
- if (!m_Device8)
- {
- return E_NOINTERFACE;
- }
- finalResourceDesc1 = *createParams.GetResourceDesc1();
- finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
- resAllocInfo = GetResourceAllocationInfo(finalResourceDesc1);
- }
- #endif
- #ifdef __ID3D12Device10_INTERFACE_DEFINED__
- else if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_LAYOUT)
- {
- if (!m_Device10)
- {
- return E_NOINTERFACE;
- }
- finalResourceDesc1 = *createParams.GetResourceDesc1();
- finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
- resAllocInfo = GetResourceAllocationInfo(finalResourceDesc1);
- }
- #endif
- else
- {
- D3D12MA_ASSERT(0);
- return E_INVALIDARG;
- }
- D3D12MA_ASSERT(IsPow2(resAllocInfo.Alignment));
- D3D12MA_ASSERT(resAllocInfo.SizeInBytes > 0);
- BlockVector* blockVector = NULL;
- CommittedAllocationParameters committedAllocationParams = {};
- bool preferCommitted = false;
-
- HRESULT hr;
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- if (createParams.Variant >= CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1)
- {
- hr = CalcAllocationParams<D3D12_RESOURCE_DESC1>(*pAllocDesc, resAllocInfo.SizeInBytes,
- createParams.GetResourceDesc1(),
- blockVector, committedAllocationParams, preferCommitted);
- }
- else
- #endif
- {
- hr = CalcAllocationParams<D3D12_RESOURCE_DESC>(*pAllocDesc, resAllocInfo.SizeInBytes,
- createParams.GetResourceDesc(),
- blockVector, committedAllocationParams, preferCommitted);
- }
- if (FAILED(hr))
- return hr;
- const bool withinBudget = (pAllocDesc->Flags & ALLOCATION_FLAG_WITHIN_BUDGET) != 0;
- hr = E_INVALIDARG;
- if (committedAllocationParams.IsValid() && preferCommitted)
- {
- hr = AllocateCommittedResource(committedAllocationParams,
- resAllocInfo.SizeInBytes, withinBudget, pAllocDesc->pPrivateData,
- finalCreateParams, ppAllocation, riidResource, ppvResource);
- if (SUCCEEDED(hr))
- return hr;
- }
- if (blockVector != NULL)
- {
- hr = blockVector->CreateResource(resAllocInfo.SizeInBytes, resAllocInfo.Alignment,
- *pAllocDesc, finalCreateParams,
- ppAllocation, riidResource, ppvResource);
- if (SUCCEEDED(hr))
- return hr;
- }
- if (committedAllocationParams.IsValid() && !preferCommitted)
- {
- hr = AllocateCommittedResource(committedAllocationParams,
- resAllocInfo.SizeInBytes, withinBudget, pAllocDesc->pPrivateData,
- finalCreateParams, ppAllocation, riidResource, ppvResource);
- if (SUCCEEDED(hr))
- return hr;
- }
- return hr;
- }
- HRESULT AllocatorPimpl::AllocateMemory(
- const ALLOCATION_DESC* pAllocDesc,
- const D3D12_RESOURCE_ALLOCATION_INFO* pAllocInfo,
- Allocation** ppAllocation)
- {
- *ppAllocation = NULL;
- BlockVector* blockVector = NULL;
- CommittedAllocationParameters committedAllocationParams = {};
- bool preferCommitted = false;
- HRESULT hr = CalcAllocationParams<D3D12_RESOURCE_DESC>(*pAllocDesc, pAllocInfo->SizeInBytes,
- NULL, // pResDesc
- blockVector, committedAllocationParams, preferCommitted);
- if (FAILED(hr))
- return hr;
- const bool withinBudget = (pAllocDesc->Flags & ALLOCATION_FLAG_WITHIN_BUDGET) != 0;
- hr = E_INVALIDARG;
- if (committedAllocationParams.IsValid() && preferCommitted)
- {
- hr = AllocateHeap(committedAllocationParams, *pAllocInfo, withinBudget, pAllocDesc->pPrivateData, ppAllocation);
- if (SUCCEEDED(hr))
- return hr;
- }
- if (blockVector != NULL)
- {
- hr = blockVector->Allocate(pAllocInfo->SizeInBytes, pAllocInfo->Alignment,
- *pAllocDesc, 1, (Allocation**)ppAllocation);
- if (SUCCEEDED(hr))
- return hr;
- }
- if (committedAllocationParams.IsValid() && !preferCommitted)
- {
- hr = AllocateHeap(committedAllocationParams, *pAllocInfo, withinBudget, pAllocDesc->pPrivateData, ppAllocation);
- if (SUCCEEDED(hr))
- return hr;
- }
- return hr;
- }
- HRESULT AllocatorPimpl::CreateAliasingResource(
- Allocation* pAllocation,
- UINT64 AllocationLocalOffset,
- const CREATE_RESOURCE_PARAMS& createParams,
- REFIID riidResource,
- void** ppvResource)
- {
- *ppvResource = NULL;
- CREATE_RESOURCE_PARAMS finalCreateParams = createParams;
- D3D12_RESOURCE_DESC finalResourceDesc;
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- D3D12_RESOURCE_DESC1 finalResourceDesc1;
- #endif
- D3D12_RESOURCE_ALLOCATION_INFO resAllocInfo;
- if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE)
- {
- finalResourceDesc = *createParams.GetResourceDesc();
- finalCreateParams.AccessResourceDesc() = &finalResourceDesc;
- resAllocInfo = GetResourceAllocationInfo(finalResourceDesc);
- }
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- else if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1)
- {
- if (!m_Device8)
- {
- return E_NOINTERFACE;
- }
- finalResourceDesc1 = *createParams.GetResourceDesc1();
- finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
- resAllocInfo = GetResourceAllocationInfo(finalResourceDesc1);
- }
- #endif
- #ifdef __ID3D12Device10_INTERFACE_DEFINED__
- else if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_LAYOUT)
- {
- if (!m_Device10)
- {
- return E_NOINTERFACE;
- }
- finalResourceDesc1 = *createParams.GetResourceDesc1();
- finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
- resAllocInfo = GetResourceAllocationInfo(finalResourceDesc1);
- }
- #endif
- else
- {
- D3D12MA_ASSERT(0);
- return E_INVALIDARG;
- }
- D3D12MA_ASSERT(IsPow2(resAllocInfo.Alignment));
- D3D12MA_ASSERT(resAllocInfo.SizeInBytes > 0);
- ID3D12Heap* const existingHeap = pAllocation->GetHeap();
- const UINT64 existingOffset = pAllocation->GetOffset();
- const UINT64 existingSize = pAllocation->GetSize();
- const UINT64 newOffset = existingOffset + AllocationLocalOffset;
- if (existingHeap == NULL ||
- AllocationLocalOffset + resAllocInfo.SizeInBytes > existingSize ||
- newOffset % resAllocInfo.Alignment != 0)
- {
- return E_INVALIDARG;
- }
- return CreatePlacedResourceWrap(existingHeap, newOffset, finalCreateParams, riidResource, ppvResource);
- }
- void AllocatorPimpl::FreeCommittedMemory(Allocation* allocation)
- {
- D3D12MA_ASSERT(allocation && allocation->m_PackedData.GetType() == Allocation::TYPE_COMMITTED);
- CommittedAllocationList* const allocList = allocation->m_Committed.list;
- allocList->Unregister(allocation);
- const UINT memSegmentGroup = allocList->GetMemorySegmentGroup(this);
- const UINT64 allocSize = allocation->GetSize();
- m_Budget.RemoveAllocation(memSegmentGroup, allocSize);
- m_Budget.RemoveBlock(memSegmentGroup, allocSize);
- }
- void AllocatorPimpl::FreePlacedMemory(Allocation* allocation)
- {
- D3D12MA_ASSERT(allocation && allocation->m_PackedData.GetType() == Allocation::TYPE_PLACED);
- NormalBlock* const block = allocation->m_Placed.block;
- D3D12MA_ASSERT(block);
- BlockVector* const blockVector = block->GetBlockVector();
- D3D12MA_ASSERT(blockVector);
- m_Budget.RemoveAllocation(HeapPropertiesToMemorySegmentGroup(block->GetHeapProperties()), allocation->GetSize());
- blockVector->Free(allocation);
- }
- void AllocatorPimpl::FreeHeapMemory(Allocation* allocation)
- {
- D3D12MA_ASSERT(allocation && allocation->m_PackedData.GetType() == Allocation::TYPE_HEAP);
- CommittedAllocationList* const allocList = allocation->m_Committed.list;
- allocList->Unregister(allocation);
- SAFE_RELEASE(allocation->m_Heap.heap);
- const UINT memSegmentGroup = allocList->GetMemorySegmentGroup(this);
- const UINT64 allocSize = allocation->GetSize();
- m_Budget.RemoveAllocation(memSegmentGroup, allocSize);
- m_Budget.RemoveBlock(memSegmentGroup, allocSize);
- }
- void AllocatorPimpl::SetResidencyPriority(ID3D12Pageable* obj, D3D12_RESIDENCY_PRIORITY priority) const
- {
- #ifdef __ID3D12Device1_INTERFACE_DEFINED__
- if (priority != D3D12_RESIDENCY_PRIORITY_NONE && m_Device1)
- {
- // Intentionally ignoring the result.
- m_Device1->SetResidencyPriority(1, &obj, &priority);
- }
- #endif
- }
- void AllocatorPimpl::SetCurrentFrameIndex(UINT frameIndex)
- {
- m_CurrentFrameIndex.store(frameIndex);
- #if D3D12MA_DXGI_1_4
- UpdateD3D12Budget();
- #endif
- }
- void AllocatorPimpl::CalculateStatistics(TotalStatistics& outStats, DetailedStatistics outCutomHeaps[2])
- {
- // Init stats
- for (size_t i = 0; i < HEAP_TYPE_COUNT; i++)
- ClearDetailedStatistics(outStats.HeapType[i]);
- for (size_t i = 0; i < DXGI_MEMORY_SEGMENT_GROUP_COUNT; i++)
- ClearDetailedStatistics(outStats.MemorySegmentGroup[i]);
- ClearDetailedStatistics(outStats.Total);
- if (outCutomHeaps)
- {
- ClearDetailedStatistics(outCutomHeaps[0]);
- ClearDetailedStatistics(outCutomHeaps[1]);
- }
- // Process default pools. 3 standard heap types only. Add them to outStats.HeapType[i].
- if (SupportsResourceHeapTier2())
- {
- // DEFAULT, UPLOAD, READBACK.
- for (size_t heapTypeIndex = 0; heapTypeIndex < STANDARD_HEAP_TYPE_COUNT; ++heapTypeIndex)
- {
- BlockVector* const pBlockVector = m_BlockVectors[heapTypeIndex];
- D3D12MA_ASSERT(pBlockVector);
- pBlockVector->AddDetailedStatistics(outStats.HeapType[heapTypeIndex]);
- }
- }
- else
- {
- // DEFAULT, UPLOAD, READBACK.
- for (size_t heapTypeIndex = 0; heapTypeIndex < STANDARD_HEAP_TYPE_COUNT; ++heapTypeIndex)
- {
- for (size_t heapSubType = 0; heapSubType < 3; ++heapSubType)
- {
- BlockVector* const pBlockVector = m_BlockVectors[heapTypeIndex * 3 + heapSubType];
- D3D12MA_ASSERT(pBlockVector);
- pBlockVector->AddDetailedStatistics(outStats.HeapType[heapTypeIndex]);
- }
- }
- }
- // Sum them up to memory segment groups.
- AddDetailedStatistics(
- outStats.MemorySegmentGroup[StandardHeapTypeToMemorySegmentGroup(D3D12_HEAP_TYPE_DEFAULT)],
- outStats.HeapType[0]);
- AddDetailedStatistics(
- outStats.MemorySegmentGroup[StandardHeapTypeToMemorySegmentGroup(D3D12_HEAP_TYPE_UPLOAD)],
- outStats.HeapType[1]);
- AddDetailedStatistics(
- outStats.MemorySegmentGroup[StandardHeapTypeToMemorySegmentGroup(D3D12_HEAP_TYPE_READBACK)],
- outStats.HeapType[2]);
- // Process custom pools.
- DetailedStatistics tmpStats;
- for (size_t heapTypeIndex = 0; heapTypeIndex < HEAP_TYPE_COUNT; ++heapTypeIndex)
- {
- MutexLockRead lock(m_PoolsMutex[heapTypeIndex], m_UseMutex);
- PoolList& poolList = m_Pools[heapTypeIndex];
- for (PoolPimpl* pool = poolList.Front(); pool != NULL; pool = poolList.GetNext(pool))
- {
- const D3D12_HEAP_PROPERTIES& poolHeapProps = pool->GetDesc().HeapProperties;
- ClearDetailedStatistics(tmpStats);
- pool->AddDetailedStatistics(tmpStats);
- AddDetailedStatistics(
- outStats.HeapType[heapTypeIndex], tmpStats);
- UINT memorySegment = HeapPropertiesToMemorySegmentGroup(poolHeapProps);
- AddDetailedStatistics(
- outStats.MemorySegmentGroup[memorySegment], tmpStats);
- if (outCutomHeaps)
- AddDetailedStatistics(outCutomHeaps[memorySegment], tmpStats);
- }
- }
- // Process committed allocations. 3 standard heap types only.
- for (UINT heapTypeIndex = 0; heapTypeIndex < STANDARD_HEAP_TYPE_COUNT; ++heapTypeIndex)
- {
- ClearDetailedStatistics(tmpStats);
- m_CommittedAllocations[heapTypeIndex].AddDetailedStatistics(tmpStats);
- AddDetailedStatistics(
- outStats.HeapType[heapTypeIndex], tmpStats);
- AddDetailedStatistics(
- outStats.MemorySegmentGroup[StandardHeapTypeToMemorySegmentGroup(IndexToHeapType(heapTypeIndex))], tmpStats);
- }
- // Sum up memory segment groups to totals.
- AddDetailedStatistics(outStats.Total, outStats.MemorySegmentGroup[0]);
- AddDetailedStatistics(outStats.Total, outStats.MemorySegmentGroup[1]);
- D3D12MA_ASSERT(outStats.Total.Stats.BlockCount ==
- outStats.MemorySegmentGroup[0].Stats.BlockCount + outStats.MemorySegmentGroup[1].Stats.BlockCount);
- D3D12MA_ASSERT(outStats.Total.Stats.AllocationCount ==
- outStats.MemorySegmentGroup[0].Stats.AllocationCount + outStats.MemorySegmentGroup[1].Stats.AllocationCount);
- D3D12MA_ASSERT(outStats.Total.Stats.BlockBytes ==
- outStats.MemorySegmentGroup[0].Stats.BlockBytes + outStats.MemorySegmentGroup[1].Stats.BlockBytes);
- D3D12MA_ASSERT(outStats.Total.Stats.AllocationBytes ==
- outStats.MemorySegmentGroup[0].Stats.AllocationBytes + outStats.MemorySegmentGroup[1].Stats.AllocationBytes);
- D3D12MA_ASSERT(outStats.Total.UnusedRangeCount ==
- outStats.MemorySegmentGroup[0].UnusedRangeCount + outStats.MemorySegmentGroup[1].UnusedRangeCount);
- D3D12MA_ASSERT(outStats.Total.Stats.BlockCount ==
- outStats.HeapType[0].Stats.BlockCount + outStats.HeapType[1].Stats.BlockCount +
- outStats.HeapType[2].Stats.BlockCount + outStats.HeapType[3].Stats.BlockCount);
- D3D12MA_ASSERT(outStats.Total.Stats.AllocationCount ==
- outStats.HeapType[0].Stats.AllocationCount + outStats.HeapType[1].Stats.AllocationCount +
- outStats.HeapType[2].Stats.AllocationCount + outStats.HeapType[3].Stats.AllocationCount);
- D3D12MA_ASSERT(outStats.Total.Stats.BlockBytes ==
- outStats.HeapType[0].Stats.BlockBytes + outStats.HeapType[1].Stats.BlockBytes +
- outStats.HeapType[2].Stats.BlockBytes + outStats.HeapType[3].Stats.BlockBytes);
- D3D12MA_ASSERT(outStats.Total.Stats.AllocationBytes ==
- outStats.HeapType[0].Stats.AllocationBytes + outStats.HeapType[1].Stats.AllocationBytes +
- outStats.HeapType[2].Stats.AllocationBytes + outStats.HeapType[3].Stats.AllocationBytes);
- D3D12MA_ASSERT(outStats.Total.UnusedRangeCount ==
- outStats.HeapType[0].UnusedRangeCount + outStats.HeapType[1].UnusedRangeCount +
- outStats.HeapType[2].UnusedRangeCount + outStats.HeapType[3].UnusedRangeCount);
- }
- void AllocatorPimpl::GetBudget(Budget* outLocalBudget, Budget* outNonLocalBudget)
- {
- if (outLocalBudget)
- m_Budget.GetStatistics(outLocalBudget->Stats, DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY);
- if (outNonLocalBudget)
- m_Budget.GetStatistics(outNonLocalBudget->Stats, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY);
- #if D3D12MA_DXGI_1_4
- if (m_Adapter3)
- {
- if (!m_Budget.ShouldUpdateBudget())
- {
- m_Budget.GetBudget(m_UseMutex,
- outLocalBudget ? &outLocalBudget->UsageBytes : NULL,
- outLocalBudget ? &outLocalBudget->BudgetBytes : NULL,
- outNonLocalBudget ? &outNonLocalBudget->UsageBytes : NULL,
- outNonLocalBudget ? &outNonLocalBudget->BudgetBytes : NULL);
- }
- else
- {
- UpdateD3D12Budget();
- GetBudget(outLocalBudget, outNonLocalBudget); // Recursion
- }
- }
- else
- #endif
- {
- if (outLocalBudget)
- {
- outLocalBudget->UsageBytes = outLocalBudget->Stats.BlockBytes;
- outLocalBudget->BudgetBytes = GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY) * 8 / 10; // 80% heuristics.
- }
- if (outNonLocalBudget)
- {
- outNonLocalBudget->UsageBytes = outNonLocalBudget->Stats.BlockBytes;
- outNonLocalBudget->BudgetBytes = GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY) * 8 / 10; // 80% heuristics.
- }
- }
- }
- void AllocatorPimpl::GetBudgetForHeapType(Budget& outBudget, D3D12_HEAP_TYPE heapType)
- {
- switch (heapType)
- {
- case D3D12_HEAP_TYPE_DEFAULT:
- GetBudget(&outBudget, NULL);
- break;
- case D3D12_HEAP_TYPE_UPLOAD:
- case D3D12_HEAP_TYPE_READBACK:
- GetBudget(NULL, &outBudget);
- break;
- default: D3D12MA_ASSERT(0);
- }
- }
- void AllocatorPimpl::BuildStatsString(WCHAR** ppStatsString, BOOL detailedMap)
- {
- StringBuilder sb(GetAllocs());
- {
- Budget localBudget = {}, nonLocalBudget = {};
- GetBudget(&localBudget, &nonLocalBudget);
- TotalStatistics stats;
- DetailedStatistics customHeaps[2];
- CalculateStatistics(stats, customHeaps);
- JsonWriter json(GetAllocs(), sb);
- json.BeginObject();
- {
- json.WriteString(L"General");
- json.BeginObject();
- {
- json.WriteString(L"API");
- json.WriteString(L"Direct3D 12");
- json.WriteString(L"GPU");
- json.WriteString(m_AdapterDesc.Description);
- json.WriteString(L"DedicatedVideoMemory");
- json.WriteNumber((UINT64)m_AdapterDesc.DedicatedVideoMemory);
- json.WriteString(L"DedicatedSystemMemory");
- json.WriteNumber((UINT64)m_AdapterDesc.DedicatedSystemMemory);
- json.WriteString(L"SharedSystemMemory");
- json.WriteNumber((UINT64)m_AdapterDesc.SharedSystemMemory);
-
- json.WriteString(L"ResourceHeapTier");
- json.WriteNumber(static_cast<UINT>(m_D3D12Options.ResourceHeapTier));
- json.WriteString(L"ResourceBindingTier");
- json.WriteNumber(static_cast<UINT>(m_D3D12Options.ResourceBindingTier));
- json.WriteString(L"TiledResourcesTier");
- json.WriteNumber(static_cast<UINT>(m_D3D12Options.TiledResourcesTier));
- json.WriteString(L"TileBasedRenderer");
- json.WriteBool(m_D3D12Architecture.TileBasedRenderer);
- json.WriteString(L"UMA");
- json.WriteBool(m_D3D12Architecture.UMA);
- json.WriteString(L"CacheCoherentUMA");
- json.WriteBool(m_D3D12Architecture.CacheCoherentUMA);
- }
- json.EndObject();
- }
- {
- json.WriteString(L"Total");
- json.AddDetailedStatisticsInfoObject(stats.Total);
- }
- {
- json.WriteString(L"MemoryInfo");
- json.BeginObject();
- {
- json.WriteString(L"L0");
- json.BeginObject();
- {
- json.WriteString(L"Budget");
- WriteBudgetToJson(json, IsUMA() ? localBudget : nonLocalBudget); // When UMA device only L0 present as local
- json.WriteString(L"Stats");
- json.AddDetailedStatisticsInfoObject(stats.MemorySegmentGroup[!IsUMA()]);
- json.WriteString(L"MemoryPools");
- json.BeginObject();
- {
- if (IsUMA())
- {
- json.WriteString(L"DEFAULT");
- json.BeginObject();
- {
- json.WriteString(L"Stats");
- json.AddDetailedStatisticsInfoObject(stats.HeapType[0]);
- }
- json.EndObject();
- }
- json.WriteString(L"UPLOAD");
- json.BeginObject();
- {
- json.WriteString(L"Stats");
- json.AddDetailedStatisticsInfoObject(stats.HeapType[1]);
- }
- json.EndObject();
- json.WriteString(L"READBACK");
- json.BeginObject();
- {
- json.WriteString(L"Stats");
- json.AddDetailedStatisticsInfoObject(stats.HeapType[2]);
- }
- json.EndObject();
- json.WriteString(L"CUSTOM");
- json.BeginObject();
- {
- json.WriteString(L"Stats");
- json.AddDetailedStatisticsInfoObject(customHeaps[!IsUMA()]);
- }
- json.EndObject();
- }
- json.EndObject();
- }
- json.EndObject();
- if (!IsUMA())
- {
- json.WriteString(L"L1");
- json.BeginObject();
- {
- json.WriteString(L"Budget");
- WriteBudgetToJson(json, localBudget);
- json.WriteString(L"Stats");
- json.AddDetailedStatisticsInfoObject(stats.MemorySegmentGroup[0]);
- json.WriteString(L"MemoryPools");
- json.BeginObject();
- {
- json.WriteString(L"DEFAULT");
- json.BeginObject();
- {
- json.WriteString(L"Stats");
- json.AddDetailedStatisticsInfoObject(stats.HeapType[0]);
- }
- json.EndObject();
- json.WriteString(L"CUSTOM");
- json.BeginObject();
- {
- json.WriteString(L"Stats");
- json.AddDetailedStatisticsInfoObject(customHeaps[0]);
- }
- json.EndObject();
- }
- json.EndObject();
- }
- json.EndObject();
- }
- }
- json.EndObject();
- }
- if (detailedMap)
- {
- const auto writeHeapInfo = [&](BlockVector* blockVector, CommittedAllocationList* committedAllocs, bool customHeap)
- {
- D3D12MA_ASSERT(blockVector);
- D3D12_HEAP_FLAGS flags = blockVector->GetHeapFlags();
- json.WriteString(L"Flags");
- json.BeginArray(true);
- {
- if (flags & D3D12_HEAP_FLAG_SHARED)
- json.WriteString(L"HEAP_FLAG_SHARED");
- if (flags & D3D12_HEAP_FLAG_ALLOW_DISPLAY)
- json.WriteString(L"HEAP_FLAG_ALLOW_DISPLAY");
- if (flags & D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER)
- json.WriteString(L"HEAP_FLAG_CROSS_ADAPTER");
- if (flags & D3D12_HEAP_FLAG_HARDWARE_PROTECTED)
- json.WriteString(L"HEAP_FLAG_HARDWARE_PROTECTED");
- if (flags & D3D12_HEAP_FLAG_ALLOW_WRITE_WATCH)
- json.WriteString(L"HEAP_FLAG_ALLOW_WRITE_WATCH");
- if (flags & D3D12_HEAP_FLAG_ALLOW_SHADER_ATOMICS)
- json.WriteString(L"HEAP_FLAG_ALLOW_SHADER_ATOMICS");
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- if (flags & D3D12_HEAP_FLAG_CREATE_NOT_RESIDENT)
- json.WriteString(L"HEAP_FLAG_CREATE_NOT_RESIDENT");
- if (flags & D3D12_HEAP_FLAG_CREATE_NOT_ZEROED)
- json.WriteString(L"HEAP_FLAG_CREATE_NOT_ZEROED");
- #endif
- if (flags & D3D12_HEAP_FLAG_DENY_BUFFERS)
- json.WriteString(L"HEAP_FLAG_DENY_BUFFERS");
- if (flags & D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES)
- json.WriteString(L"HEAP_FLAG_DENY_RT_DS_TEXTURES");
- if (flags & D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES)
- json.WriteString(L"HEAP_FLAG_DENY_NON_RT_DS_TEXTURES");
- flags &= ~(D3D12_HEAP_FLAG_SHARED
- | D3D12_HEAP_FLAG_DENY_BUFFERS
- | D3D12_HEAP_FLAG_ALLOW_DISPLAY
- | D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER
- | D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES
- | D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES
- | D3D12_HEAP_FLAG_HARDWARE_PROTECTED
- | D3D12_HEAP_FLAG_ALLOW_WRITE_WATCH
- | D3D12_HEAP_FLAG_ALLOW_SHADER_ATOMICS);
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- flags &= ~(D3D12_HEAP_FLAG_CREATE_NOT_RESIDENT
- | D3D12_HEAP_FLAG_CREATE_NOT_ZEROED);
- #endif
- if (flags != 0)
- json.WriteNumber((UINT)flags);
- if (customHeap)
- {
- const D3D12_HEAP_PROPERTIES& properties = blockVector->GetHeapProperties();
- switch (properties.MemoryPoolPreference)
- {
- default:
- D3D12MA_ASSERT(0);
- case D3D12_MEMORY_POOL_UNKNOWN:
- json.WriteString(L"MEMORY_POOL_UNKNOWN");
- break;
- case D3D12_MEMORY_POOL_L0:
- json.WriteString(L"MEMORY_POOL_L0");
- break;
- case D3D12_MEMORY_POOL_L1:
- json.WriteString(L"MEMORY_POOL_L1");
- break;
- }
- switch (properties.CPUPageProperty)
- {
- default:
- D3D12MA_ASSERT(0);
- case D3D12_CPU_PAGE_PROPERTY_UNKNOWN:
- json.WriteString(L"CPU_PAGE_PROPERTY_UNKNOWN");
- break;
- case D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE:
- json.WriteString(L"CPU_PAGE_PROPERTY_NOT_AVAILABLE");
- break;
- case D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE:
- json.WriteString(L"CPU_PAGE_PROPERTY_WRITE_COMBINE");
- break;
- case D3D12_CPU_PAGE_PROPERTY_WRITE_BACK:
- json.WriteString(L"CPU_PAGE_PROPERTY_WRITE_BACK");
- break;
- }
- }
- }
- json.EndArray();
- json.WriteString(L"PreferredBlockSize");
- json.WriteNumber(blockVector->GetPreferredBlockSize());
- json.WriteString(L"Blocks");
- blockVector->WriteBlockInfoToJson(json);
- json.WriteString(L"DedicatedAllocations");
- json.BeginArray();
- if (committedAllocs)
- committedAllocs->BuildStatsString(json);
- json.EndArray();
- };
- json.WriteString(L"DefaultPools");
- json.BeginObject();
- {
- if (SupportsResourceHeapTier2())
- {
- for (uint8_t heapType = 0; heapType < STANDARD_HEAP_TYPE_COUNT; ++heapType)
- {
- json.WriteString(HeapTypeNames[heapType]);
- json.BeginObject();
- writeHeapInfo(m_BlockVectors[heapType], m_CommittedAllocations + heapType, false);
- json.EndObject();
- }
- }
- else
- {
- for (uint8_t heapType = 0; heapType < STANDARD_HEAP_TYPE_COUNT; ++heapType)
- {
- for (uint8_t heapSubType = 0; heapSubType < 3; ++heapSubType)
- {
- static const WCHAR* const heapSubTypeName[] = {
- L" - Buffers",
- L" - Textures",
- L" - Textures RT/DS",
- };
- json.BeginString(HeapTypeNames[heapType]);
- json.EndString(heapSubTypeName[heapSubType]);
- json.BeginObject();
- writeHeapInfo(m_BlockVectors[heapType + heapSubType], m_CommittedAllocations + heapType, false);
- json.EndObject();
- }
- }
- }
- }
- json.EndObject();
- json.WriteString(L"CustomPools");
- json.BeginObject();
- for (uint8_t heapTypeIndex = 0; heapTypeIndex < HEAP_TYPE_COUNT; ++heapTypeIndex)
- {
- MutexLockRead mutex(m_PoolsMutex[heapTypeIndex], m_UseMutex);
- auto* item = m_Pools[heapTypeIndex].Front();
- if (item != NULL)
- {
- size_t index = 0;
- json.WriteString(HeapTypeNames[heapTypeIndex]);
- json.BeginArray();
- do
- {
- json.BeginObject();
- json.WriteString(L"Name");
- json.BeginString();
- json.ContinueString(index++);
- if (item->GetName())
- {
- json.ContinueString(L" - ");
- json.ContinueString(item->GetName());
- }
- json.EndString();
- writeHeapInfo(item->GetBlockVector(), item->GetCommittedAllocationList(), heapTypeIndex == 3);
- json.EndObject();
- } while ((item = PoolList::GetNext(item)) != NULL);
- json.EndArray();
- }
- }
- json.EndObject();
- }
- json.EndObject();
- }
- const size_t length = sb.GetLength();
- WCHAR* result = AllocateArray<WCHAR>(GetAllocs(), length + 2);
- result[0] = 0xFEFF;
- memcpy(result + 1, sb.GetData(), length * sizeof(WCHAR));
- result[length + 1] = L'\0';
- *ppStatsString = result;
- }
- void AllocatorPimpl::FreeStatsString(WCHAR* pStatsString)
- {
- D3D12MA_ASSERT(pStatsString);
- Free(GetAllocs(), pStatsString);
- }
- template<typename D3D12_RESOURCE_DESC_T>
- bool AllocatorPimpl::PrefersCommittedAllocation(const D3D12_RESOURCE_DESC_T& resourceDesc)
- {
- // Intentional. It may change in the future.
- return false;
- }
- HRESULT AllocatorPimpl::AllocateCommittedResource(
- const CommittedAllocationParameters& committedAllocParams,
- UINT64 resourceSize, bool withinBudget, void* pPrivateData,
- const CREATE_RESOURCE_PARAMS& createParams,
- Allocation** ppAllocation, REFIID riidResource, void** ppvResource)
- {
- D3D12MA_ASSERT(committedAllocParams.IsValid());
- HRESULT hr;
- ID3D12Resource* res = NULL;
- // Allocate aliasing memory with explicit heap
- if (committedAllocParams.m_CanAlias)
- {
- D3D12_RESOURCE_ALLOCATION_INFO heapAllocInfo = {};
- heapAllocInfo.SizeInBytes = resourceSize;
- heapAllocInfo.Alignment = HeapFlagsToAlignment(committedAllocParams.m_HeapFlags, m_MsaaAlwaysCommitted);
- hr = AllocateHeap(committedAllocParams, heapAllocInfo, withinBudget, pPrivateData, ppAllocation);
- if (SUCCEEDED(hr))
- {
- hr = CreatePlacedResourceWrap((*ppAllocation)->GetHeap(), 0,
- createParams, D3D12MA_IID_PPV_ARGS(&res));
- if (SUCCEEDED(hr))
- {
- if (ppvResource != NULL)
- hr = res->QueryInterface(riidResource, ppvResource);
- if (SUCCEEDED(hr))
- {
- (*ppAllocation)->SetResourcePointer(res, createParams.GetBaseResourceDesc());
- return hr;
- }
- res->Release();
- }
- FreeHeapMemory(*ppAllocation);
- }
- return hr;
- }
- if (withinBudget &&
- !NewAllocationWithinBudget(committedAllocParams.m_HeapProperties.Type, resourceSize))
- {
- return E_OUTOFMEMORY;
- }
- /* D3D12 ERROR:
- * ID3D12Device::CreateCommittedResource:
- * When creating a committed resource, D3D12_HEAP_FLAGS must not have either
- * D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES,
- * D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES,
- * nor D3D12_HEAP_FLAG_DENY_BUFFERS set.
- * These flags will be set automatically to correspond with the committed resource type.
- *
- * [ STATE_CREATION ERROR #640: CREATERESOURCEANDHEAP_INVALIDHEAPMISCFLAGS]
- */
- #ifdef __ID3D12Device10_INTERFACE_DEFINED__
- if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_LAYOUT)
- {
- if (!m_Device10)
- {
- return E_NOINTERFACE;
- }
- hr = m_Device10->CreateCommittedResource3(
- &committedAllocParams.m_HeapProperties,
- committedAllocParams.m_HeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS,
- createParams.GetResourceDesc1(), createParams.GetInitialLayout(),
- createParams.GetOptimizedClearValue(), committedAllocParams.m_ProtectedSession,
- createParams.GetNumCastableFormats(), createParams.GetCastableFormats(),
- D3D12MA_IID_PPV_ARGS(&res));
- } else
- #endif
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1)
- {
- if (!m_Device8)
- {
- return E_NOINTERFACE;
- }
- hr = m_Device8->CreateCommittedResource2(
- &committedAllocParams.m_HeapProperties,
- committedAllocParams.m_HeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS,
- createParams.GetResourceDesc1(), createParams.GetInitialResourceState(),
- createParams.GetOptimizedClearValue(), committedAllocParams.m_ProtectedSession,
- D3D12MA_IID_PPV_ARGS(&res));
- } else
- #endif
- if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE)
- {
- #ifdef __ID3D12Device4_INTERFACE_DEFINED__
- if (m_Device4)
- {
- hr = m_Device4->CreateCommittedResource1(
- &committedAllocParams.m_HeapProperties,
- committedAllocParams.m_HeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS,
- createParams.GetResourceDesc(), createParams.GetInitialResourceState(),
- createParams.GetOptimizedClearValue(), committedAllocParams.m_ProtectedSession,
- D3D12MA_IID_PPV_ARGS(&res));
- }
- else
- #endif
- {
- if (committedAllocParams.m_ProtectedSession == NULL)
- {
- hr = m_Device->CreateCommittedResource(
- &committedAllocParams.m_HeapProperties,
- committedAllocParams.m_HeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS,
- createParams.GetResourceDesc(), createParams.GetInitialResourceState(),
- createParams.GetOptimizedClearValue(), D3D12MA_IID_PPV_ARGS(&res));
- }
- else
- hr = E_NOINTERFACE;
- }
- }
- else
- {
- D3D12MA_ASSERT(0);
- return E_INVALIDARG;
- }
- if (SUCCEEDED(hr))
- {
- SetResidencyPriority(res, committedAllocParams.m_ResidencyPriority);
- if (ppvResource != NULL)
- {
- hr = res->QueryInterface(riidResource, ppvResource);
- }
- if (SUCCEEDED(hr))
- {
- BOOL wasZeroInitialized = TRUE;
- #if D3D12MA_CREATE_NOT_ZEROED_AVAILABLE
- if((committedAllocParams.m_HeapFlags & D3D12_HEAP_FLAG_CREATE_NOT_ZEROED) != 0)
- {
- wasZeroInitialized = FALSE;
- }
- #endif
- Allocation* alloc = m_AllocationObjectAllocator.Allocate(
- this, resourceSize, createParams.GetBaseResourceDesc()->Alignment, wasZeroInitialized);
- alloc->InitCommitted(committedAllocParams.m_List);
- alloc->SetResourcePointer(res, createParams.GetBaseResourceDesc());
- alloc->SetPrivateData(pPrivateData);
- *ppAllocation = alloc;
- committedAllocParams.m_List->Register(alloc);
- const UINT memSegmentGroup = HeapPropertiesToMemorySegmentGroup(committedAllocParams.m_HeapProperties);
- m_Budget.AddBlock(memSegmentGroup, resourceSize);
- m_Budget.AddAllocation(memSegmentGroup, resourceSize);
- }
- else
- {
- res->Release();
- }
- }
- return hr;
- }
- HRESULT AllocatorPimpl::AllocateHeap(
- const CommittedAllocationParameters& committedAllocParams,
- const D3D12_RESOURCE_ALLOCATION_INFO& allocInfo, bool withinBudget,
- void* pPrivateData, Allocation** ppAllocation)
- {
- D3D12MA_ASSERT(committedAllocParams.IsValid());
- *ppAllocation = nullptr;
- if (withinBudget &&
- !NewAllocationWithinBudget(committedAllocParams.m_HeapProperties.Type, allocInfo.SizeInBytes))
- {
- return E_OUTOFMEMORY;
- }
- D3D12_HEAP_DESC heapDesc = {};
- heapDesc.SizeInBytes = allocInfo.SizeInBytes;
- heapDesc.Properties = committedAllocParams.m_HeapProperties;
- heapDesc.Alignment = allocInfo.Alignment;
- heapDesc.Flags = committedAllocParams.m_HeapFlags;
- HRESULT hr;
- ID3D12Heap* heap = nullptr;
- #ifdef __ID3D12Device4_INTERFACE_DEFINED__
- if (m_Device4)
- hr = m_Device4->CreateHeap1(&heapDesc, committedAllocParams.m_ProtectedSession, D3D12MA_IID_PPV_ARGS(&heap));
- else
- #endif
- {
- if (committedAllocParams.m_ProtectedSession == NULL)
- hr = m_Device->CreateHeap(&heapDesc, D3D12MA_IID_PPV_ARGS(&heap));
- else
- hr = E_NOINTERFACE;
- }
- if (SUCCEEDED(hr))
- {
- SetResidencyPriority(heap, committedAllocParams.m_ResidencyPriority);
- BOOL wasZeroInitialized = TRUE;
- #if D3D12MA_CREATE_NOT_ZEROED_AVAILABLE
- if((heapDesc.Flags & D3D12_HEAP_FLAG_CREATE_NOT_ZEROED) != 0)
- {
- wasZeroInitialized = FALSE;
- }
- #endif
- (*ppAllocation) = m_AllocationObjectAllocator.Allocate(this, allocInfo.SizeInBytes, allocInfo.Alignment, wasZeroInitialized);
- (*ppAllocation)->InitHeap(committedAllocParams.m_List, heap);
- (*ppAllocation)->SetPrivateData(pPrivateData);
- committedAllocParams.m_List->Register(*ppAllocation);
- const UINT memSegmentGroup = HeapPropertiesToMemorySegmentGroup(committedAllocParams.m_HeapProperties);
- m_Budget.AddBlock(memSegmentGroup, allocInfo.SizeInBytes);
- m_Budget.AddAllocation(memSegmentGroup, allocInfo.SizeInBytes);
- }
- return hr;
- }
- template<typename D3D12_RESOURCE_DESC_T>
- HRESULT AllocatorPimpl::CalcAllocationParams(const ALLOCATION_DESC& allocDesc, UINT64 allocSize,
- const D3D12_RESOURCE_DESC_T* resDesc,
- BlockVector*& outBlockVector, CommittedAllocationParameters& outCommittedAllocationParams, bool& outPreferCommitted)
- {
- outBlockVector = NULL;
- outCommittedAllocationParams = CommittedAllocationParameters();
- outPreferCommitted = false;
- bool msaaAlwaysCommitted;
- if (allocDesc.CustomPool != NULL)
- {
- PoolPimpl* const pool = allocDesc.CustomPool->m_Pimpl;
- msaaAlwaysCommitted = pool->GetBlockVector()->DeniesMsaaTextures();
- outBlockVector = pool->GetBlockVector();
- const auto& desc = pool->GetDesc();
- outCommittedAllocationParams.m_ProtectedSession = desc.pProtectedSession;
- outCommittedAllocationParams.m_HeapProperties = desc.HeapProperties;
- outCommittedAllocationParams.m_HeapFlags = desc.HeapFlags;
- outCommittedAllocationParams.m_List = pool->GetCommittedAllocationList();
- outCommittedAllocationParams.m_ResidencyPriority = pool->GetDesc().ResidencyPriority;
- }
- else
- {
- if (!IsHeapTypeStandard(allocDesc.HeapType))
- {
- return E_INVALIDARG;
- }
- msaaAlwaysCommitted = m_MsaaAlwaysCommitted;
- outCommittedAllocationParams.m_HeapProperties = StandardHeapTypeToHeapProperties(allocDesc.HeapType);
- outCommittedAllocationParams.m_HeapFlags = allocDesc.ExtraHeapFlags;
- outCommittedAllocationParams.m_List = &m_CommittedAllocations[HeapTypeToIndex(allocDesc.HeapType)];
- // outCommittedAllocationParams.m_ResidencyPriority intentionally left with default value.
- const ResourceClass resourceClass = (resDesc != NULL) ?
- ResourceDescToResourceClass(*resDesc) : HeapFlagsToResourceClass(allocDesc.ExtraHeapFlags);
- const UINT defaultPoolIndex = CalcDefaultPoolIndex(allocDesc, resourceClass);
- if (defaultPoolIndex != UINT32_MAX)
- {
- outBlockVector = m_BlockVectors[defaultPoolIndex];
- const UINT64 preferredBlockSize = outBlockVector->GetPreferredBlockSize();
- if (allocSize > preferredBlockSize)
- {
- outBlockVector = NULL;
- }
- else if (allocSize > preferredBlockSize / 2)
- {
- // Heuristics: Allocate committed memory if requested size if greater than half of preferred block size.
- outPreferCommitted = true;
- }
- }
- const D3D12_HEAP_FLAGS extraHeapFlags = allocDesc.ExtraHeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS;
- if (outBlockVector != NULL && extraHeapFlags != 0)
- {
- outBlockVector = NULL;
- }
- }
- if ((allocDesc.Flags & ALLOCATION_FLAG_COMMITTED) != 0 ||
- m_AlwaysCommitted)
- {
- outBlockVector = NULL;
- }
- if ((allocDesc.Flags & ALLOCATION_FLAG_NEVER_ALLOCATE) != 0)
- {
- outCommittedAllocationParams.m_List = NULL;
- }
- outCommittedAllocationParams.m_CanAlias = allocDesc.Flags & ALLOCATION_FLAG_CAN_ALIAS;
- if (resDesc != NULL)
- {
- if (resDesc->SampleDesc.Count > 1 && msaaAlwaysCommitted)
- outBlockVector = NULL;
- if (!outPreferCommitted && PrefersCommittedAllocation(*resDesc))
- outPreferCommitted = true;
- }
- return (outBlockVector != NULL || outCommittedAllocationParams.m_List != NULL) ? S_OK : E_INVALIDARG;
- }
- UINT AllocatorPimpl::CalcDefaultPoolIndex(const ALLOCATION_DESC& allocDesc, ResourceClass resourceClass) const
- {
- D3D12_HEAP_FLAGS extraHeapFlags = allocDesc.ExtraHeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS;
- #if D3D12MA_CREATE_NOT_ZEROED_AVAILABLE
- // If allocator was created with ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED, also ignore
- // D3D12_HEAP_FLAG_CREATE_NOT_ZEROED.
- if(m_DefaultPoolsNotZeroed)
- {
- extraHeapFlags &= ~D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;
- }
- #endif
- if (extraHeapFlags != 0)
- {
- return UINT32_MAX;
- }
- UINT poolIndex = UINT_MAX;
- switch (allocDesc.HeapType)
- {
- case D3D12_HEAP_TYPE_DEFAULT: poolIndex = 0; break;
- case D3D12_HEAP_TYPE_UPLOAD: poolIndex = 1; break;
- case D3D12_HEAP_TYPE_READBACK: poolIndex = 2; break;
- default: D3D12MA_ASSERT(0);
- }
- if (SupportsResourceHeapTier2())
- return poolIndex;
- else
- {
- switch (resourceClass)
- {
- case ResourceClass::Buffer:
- return poolIndex * 3;
- case ResourceClass::Non_RT_DS_Texture:
- return poolIndex * 3 + 1;
- case ResourceClass::RT_DS_Texture:
- return poolIndex * 3 + 2;
- default:
- return UINT32_MAX;
- }
- }
- }
- void AllocatorPimpl::CalcDefaultPoolParams(D3D12_HEAP_TYPE& outHeapType, D3D12_HEAP_FLAGS& outHeapFlags, UINT index) const
- {
- outHeapType = D3D12_HEAP_TYPE_DEFAULT;
- outHeapFlags = D3D12_HEAP_FLAG_NONE;
- if (!SupportsResourceHeapTier2())
- {
- switch (index % 3)
- {
- case 0:
- outHeapFlags = D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES | D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
- break;
- case 1:
- outHeapFlags = D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES;
- break;
- case 2:
- outHeapFlags = D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
- break;
- }
- index /= 3;
- }
- switch (index)
- {
- case 0:
- outHeapType = D3D12_HEAP_TYPE_DEFAULT;
- break;
- case 1:
- outHeapType = D3D12_HEAP_TYPE_UPLOAD;
- break;
- case 2:
- outHeapType = D3D12_HEAP_TYPE_READBACK;
- break;
- default:
- D3D12MA_ASSERT(0);
- }
- }
- void AllocatorPimpl::RegisterPool(Pool* pool, D3D12_HEAP_TYPE heapType)
- {
- const UINT heapTypeIndex = HeapTypeToIndex(heapType);
- MutexLockWrite lock(m_PoolsMutex[heapTypeIndex], m_UseMutex);
- m_Pools[heapTypeIndex].PushBack(pool->m_Pimpl);
- }
- void AllocatorPimpl::UnregisterPool(Pool* pool, D3D12_HEAP_TYPE heapType)
- {
- const UINT heapTypeIndex = HeapTypeToIndex(heapType);
- MutexLockWrite lock(m_PoolsMutex[heapTypeIndex], m_UseMutex);
- m_Pools[heapTypeIndex].Remove(pool->m_Pimpl);
- }
- HRESULT AllocatorPimpl::UpdateD3D12Budget()
- {
- #if D3D12MA_DXGI_1_4
- if (m_Adapter3)
- return m_Budget.UpdateBudget(m_Adapter3, m_UseMutex);
- else
- return E_NOINTERFACE;
- #else
- return S_OK;
- #endif
- }
- D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfoNative(const D3D12_RESOURCE_DESC& resourceDesc) const
- {
- #if defined(_MSC_VER) || !defined(_WIN32)
- return m_Device->GetResourceAllocationInfo(0, 1, &resourceDesc);
- #else
- D3D12_RESOURCE_ALLOCATION_INFO ret;
- m_Device->GetResourceAllocationInfo(&ret, 0, 1, &resourceDesc);
- return ret;
- #endif
- }
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfoNative(const D3D12_RESOURCE_DESC1& resourceDesc) const
- {
- D3D12MA_ASSERT(m_Device8 != NULL);
- D3D12_RESOURCE_ALLOCATION_INFO1 info1Unused;
- #if defined(_MSC_VER) || !defined(_WIN32)
- return m_Device8->GetResourceAllocationInfo2(0, 1, &resourceDesc, &info1Unused);
- #else
- D3D12_RESOURCE_ALLOCATION_INFO ret;
- m_Device8->GetResourceAllocationInfo2(&ret, 0, 1, &resourceDesc, &info1Unused);
- return ret;
- #endif
- }
- #endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- template<typename D3D12_RESOURCE_DESC_T>
- D3D12_RESOURCE_ALLOCATION_INFO AllocatorPimpl::GetResourceAllocationInfo(D3D12_RESOURCE_DESC_T& inOutResourceDesc) const
- {
- /* Optional optimization: Microsoft documentation says:
- https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-getresourceallocationinfo
- Your application can forgo using GetResourceAllocationInfo for buffer resources
- (D3D12_RESOURCE_DIMENSION_BUFFER). Buffers have the same size on all adapters,
- which is merely the smallest multiple of 64KB that's greater or equal to
- D3D12_RESOURCE_DESC::Width.
- */
- if (inOutResourceDesc.Alignment == 0 &&
- inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
- {
- return {
- AlignUp<UINT64>(inOutResourceDesc.Width, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT), // SizeInBytes
- D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT }; // Alignment
- }
- #if D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT
- if (inOutResourceDesc.Alignment == 0 &&
- inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D &&
- (inOutResourceDesc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) == 0
- #if D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT == 1
- && CanUseSmallAlignment(inOutResourceDesc)
- #endif
- )
- {
- /*
- The algorithm here is based on Microsoft sample: "Small Resources Sample"
- https://github.com/microsoft/DirectX-Graphics-Samples/tree/master/Samples/Desktop/D3D12SmallResources
- */
- const UINT64 smallAlignmentToTry = inOutResourceDesc.SampleDesc.Count > 1 ?
- D3D12_SMALL_MSAA_RESOURCE_PLACEMENT_ALIGNMENT :
- D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT;
- inOutResourceDesc.Alignment = smallAlignmentToTry;
- const D3D12_RESOURCE_ALLOCATION_INFO smallAllocInfo = GetResourceAllocationInfoNative(inOutResourceDesc);
- // Check if alignment requested has been granted.
- if (smallAllocInfo.Alignment == smallAlignmentToTry)
- {
- return smallAllocInfo;
- }
- inOutResourceDesc.Alignment = 0; // Restore original
- }
- #endif // #if D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT
- return GetResourceAllocationInfoNative(inOutResourceDesc);
- }
- bool AllocatorPimpl::NewAllocationWithinBudget(D3D12_HEAP_TYPE heapType, UINT64 size)
- {
- Budget budget = {};
- GetBudgetForHeapType(budget, heapType);
- return budget.UsageBytes + size <= budget.BudgetBytes;
- }
- void AllocatorPimpl::WriteBudgetToJson(JsonWriter& json, const Budget& budget)
- {
- json.BeginObject();
- {
- json.WriteString(L"BudgetBytes");
- json.WriteNumber(budget.BudgetBytes);
- json.WriteString(L"UsageBytes");
- json.WriteNumber(budget.UsageBytes);
- }
- json.EndObject();
- }
- #endif // _D3D12MA_ALLOCATOR_PIMPL
- #endif // _D3D12MA_ALLOCATOR_PIMPL
- #ifndef _D3D12MA_VIRTUAL_BLOCK_PIMPL
- class VirtualBlockPimpl
- {
- public:
- const ALLOCATION_CALLBACKS m_AllocationCallbacks;
- const UINT64 m_Size;
- BlockMetadata* m_Metadata;
- VirtualBlockPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks, const VIRTUAL_BLOCK_DESC& desc);
- ~VirtualBlockPimpl();
- };
- #ifndef _D3D12MA_VIRTUAL_BLOCK_PIMPL_FUNCTIONS
- VirtualBlockPimpl::VirtualBlockPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks, const VIRTUAL_BLOCK_DESC& desc)
- : m_AllocationCallbacks(allocationCallbacks), m_Size(desc.Size)
- {
- switch (desc.Flags & VIRTUAL_BLOCK_FLAG_ALGORITHM_MASK)
- {
- case VIRTUAL_BLOCK_FLAG_ALGORITHM_LINEAR:
- m_Metadata = D3D12MA_NEW(allocationCallbacks, BlockMetadata_Linear)(&m_AllocationCallbacks, true);
- break;
- default:
- D3D12MA_ASSERT(0);
- case 0:
- m_Metadata = D3D12MA_NEW(allocationCallbacks, BlockMetadata_TLSF)(&m_AllocationCallbacks, true);
- break;
- }
- m_Metadata->Init(m_Size);
- }
- VirtualBlockPimpl::~VirtualBlockPimpl()
- {
- D3D12MA_DELETE(m_AllocationCallbacks, m_Metadata);
- }
- #endif // _D3D12MA_VIRTUAL_BLOCK_PIMPL_FUNCTIONS
- #endif // _D3D12MA_VIRTUAL_BLOCK_PIMPL
- #ifndef _D3D12MA_MEMORY_BLOCK_FUNCTIONS
- MemoryBlock::MemoryBlock(
- AllocatorPimpl* allocator,
- const D3D12_HEAP_PROPERTIES& heapProps,
- D3D12_HEAP_FLAGS heapFlags,
- UINT64 size,
- UINT id)
- : m_Allocator(allocator),
- m_HeapProps(heapProps),
- m_HeapFlags(heapFlags),
- m_Size(size),
- m_Id(id) {}
- MemoryBlock::~MemoryBlock()
- {
- if (m_Heap)
- {
- m_Heap->Release();
- m_Allocator->m_Budget.RemoveBlock(
- m_Allocator->HeapPropertiesToMemorySegmentGroup(m_HeapProps), m_Size);
- }
- }
- HRESULT MemoryBlock::Init(ID3D12ProtectedResourceSession* pProtectedSession, bool denyMsaaTextures)
- {
- D3D12MA_ASSERT(m_Heap == NULL && m_Size > 0);
- D3D12_HEAP_DESC heapDesc = {};
- heapDesc.SizeInBytes = m_Size;
- heapDesc.Properties = m_HeapProps;
- heapDesc.Alignment = HeapFlagsToAlignment(m_HeapFlags, denyMsaaTextures);
- heapDesc.Flags = m_HeapFlags;
- HRESULT hr;
- #ifdef __ID3D12Device4_INTERFACE_DEFINED__
- ID3D12Device4* const device4 = m_Allocator->GetDevice4();
- if (device4)
- hr = m_Allocator->GetDevice4()->CreateHeap1(&heapDesc, pProtectedSession, D3D12MA_IID_PPV_ARGS(&m_Heap));
- else
- #endif
- {
- if (pProtectedSession == NULL)
- hr = m_Allocator->GetDevice()->CreateHeap(&heapDesc, D3D12MA_IID_PPV_ARGS(&m_Heap));
- else
- hr = E_NOINTERFACE;
- }
- if (SUCCEEDED(hr))
- {
- m_Allocator->m_Budget.AddBlock(
- m_Allocator->HeapPropertiesToMemorySegmentGroup(m_HeapProps), m_Size);
- }
- return hr;
- }
- #endif // _D3D12MA_MEMORY_BLOCK_FUNCTIONS
- #ifndef _D3D12MA_NORMAL_BLOCK_FUNCTIONS
- NormalBlock::NormalBlock(
- AllocatorPimpl* allocator,
- BlockVector* blockVector,
- const D3D12_HEAP_PROPERTIES& heapProps,
- D3D12_HEAP_FLAGS heapFlags,
- UINT64 size,
- UINT id)
- : MemoryBlock(allocator, heapProps, heapFlags, size, id),
- m_pMetadata(NULL),
- m_BlockVector(blockVector) {}
- NormalBlock::~NormalBlock()
- {
- if (m_pMetadata != NULL)
- {
- // Define macro D3D12MA_DEBUG_LOG to receive the list of the unfreed allocations.
- if (!m_pMetadata->IsEmpty())
- m_pMetadata->DebugLogAllAllocations();
- // THIS IS THE MOST IMPORTANT ASSERT IN THE ENTIRE LIBRARY!
- // Hitting it means you have some memory leak - unreleased Allocation objects.
- D3D12MA_ASSERT(m_pMetadata->IsEmpty() && "Some allocations were not freed before destruction of this memory block!");
- D3D12MA_DELETE(m_Allocator->GetAllocs(), m_pMetadata);
- }
- }
- HRESULT NormalBlock::Init(UINT32 algorithm, ID3D12ProtectedResourceSession* pProtectedSession, bool denyMsaaTextures)
- {
- HRESULT hr = MemoryBlock::Init(pProtectedSession, denyMsaaTextures);
- if (FAILED(hr))
- {
- return hr;
- }
- switch (algorithm)
- {
- case POOL_FLAG_ALGORITHM_LINEAR:
- m_pMetadata = D3D12MA_NEW(m_Allocator->GetAllocs(), BlockMetadata_Linear)(&m_Allocator->GetAllocs(), false);
- break;
- default:
- D3D12MA_ASSERT(0);
- case 0:
- m_pMetadata = D3D12MA_NEW(m_Allocator->GetAllocs(), BlockMetadata_TLSF)(&m_Allocator->GetAllocs(), false);
- break;
- }
- m_pMetadata->Init(m_Size);
- return hr;
- }
- bool NormalBlock::Validate() const
- {
- D3D12MA_VALIDATE(GetHeap() &&
- m_pMetadata &&
- m_pMetadata->GetSize() != 0 &&
- m_pMetadata->GetSize() == GetSize());
- return m_pMetadata->Validate();
- }
- #endif // _D3D12MA_NORMAL_BLOCK_FUNCTIONS
- #ifndef _D3D12MA_COMMITTED_ALLOCATION_LIST_FUNCTIONS
- void CommittedAllocationList::Init(bool useMutex, D3D12_HEAP_TYPE heapType, PoolPimpl* pool)
- {
- m_UseMutex = useMutex;
- m_HeapType = heapType;
- m_Pool = pool;
- }
- CommittedAllocationList::~CommittedAllocationList()
- {
- if (!m_AllocationList.IsEmpty())
- {
- D3D12MA_ASSERT(0 && "Unfreed committed allocations found!");
- }
- }
- UINT CommittedAllocationList::GetMemorySegmentGroup(AllocatorPimpl* allocator) const
- {
- if (m_Pool)
- return allocator->HeapPropertiesToMemorySegmentGroup(m_Pool->GetDesc().HeapProperties);
- else
- return allocator->StandardHeapTypeToMemorySegmentGroup(m_HeapType);
- }
- void CommittedAllocationList::AddStatistics(Statistics& inoutStats)
- {
- MutexLockRead lock(m_Mutex, m_UseMutex);
- for (Allocation* alloc = m_AllocationList.Front();
- alloc != NULL; alloc = m_AllocationList.GetNext(alloc))
- {
- const UINT64 size = alloc->GetSize();
- inoutStats.BlockCount++;
- inoutStats.AllocationCount++;
- inoutStats.BlockBytes += size;
- inoutStats.AllocationBytes += size;
- }
- }
- void CommittedAllocationList::AddDetailedStatistics(DetailedStatistics& inoutStats)
- {
- MutexLockRead lock(m_Mutex, m_UseMutex);
- for (Allocation* alloc = m_AllocationList.Front();
- alloc != NULL; alloc = m_AllocationList.GetNext(alloc))
- {
- const UINT64 size = alloc->GetSize();
- inoutStats.Stats.BlockCount++;
- inoutStats.Stats.BlockBytes += size;
- AddDetailedStatisticsAllocation(inoutStats, size);
- }
- }
- void CommittedAllocationList::BuildStatsString(JsonWriter& json)
- {
- MutexLockRead lock(m_Mutex, m_UseMutex);
- for (Allocation* alloc = m_AllocationList.Front();
- alloc != NULL; alloc = m_AllocationList.GetNext(alloc))
- {
- json.BeginObject(true);
- json.AddAllocationToObject(*alloc);
- json.EndObject();
- }
- }
- void CommittedAllocationList::Register(Allocation* alloc)
- {
- MutexLockWrite lock(m_Mutex, m_UseMutex);
- m_AllocationList.PushBack(alloc);
- }
- void CommittedAllocationList::Unregister(Allocation* alloc)
- {
- MutexLockWrite lock(m_Mutex, m_UseMutex);
- m_AllocationList.Remove(alloc);
- }
- #endif // _D3D12MA_COMMITTED_ALLOCATION_LIST_FUNCTIONS
- #ifndef _D3D12MA_BLOCK_VECTOR_FUNCTIONS
- BlockVector::BlockVector(
- AllocatorPimpl* hAllocator,
- const D3D12_HEAP_PROPERTIES& heapProps,
- D3D12_HEAP_FLAGS heapFlags,
- UINT64 preferredBlockSize,
- size_t minBlockCount,
- size_t maxBlockCount,
- bool explicitBlockSize,
- UINT64 minAllocationAlignment,
- UINT32 algorithm,
- bool denyMsaaTextures,
- ID3D12ProtectedResourceSession* pProtectedSession,
- D3D12_RESIDENCY_PRIORITY residencyPriority)
- : m_hAllocator(hAllocator),
- m_HeapProps(heapProps),
- m_HeapFlags(heapFlags),
- m_PreferredBlockSize(preferredBlockSize),
- m_MinBlockCount(minBlockCount),
- m_MaxBlockCount(maxBlockCount),
- m_ExplicitBlockSize(explicitBlockSize),
- m_MinAllocationAlignment(minAllocationAlignment),
- m_Algorithm(algorithm),
- m_DenyMsaaTextures(denyMsaaTextures),
- m_ProtectedSession(pProtectedSession),
- m_ResidencyPriority(residencyPriority),
- m_HasEmptyBlock(false),
- m_Blocks(hAllocator->GetAllocs()),
- m_NextBlockId(0) {}
- BlockVector::~BlockVector()
- {
- for (size_t i = m_Blocks.size(); i--; )
- {
- D3D12MA_DELETE(m_hAllocator->GetAllocs(), m_Blocks[i]);
- }
- }
- HRESULT BlockVector::CreateMinBlocks()
- {
- for (size_t i = 0; i < m_MinBlockCount; ++i)
- {
- HRESULT hr = CreateBlock(m_PreferredBlockSize, NULL);
- if (FAILED(hr))
- {
- return hr;
- }
- }
- return S_OK;
- }
- bool BlockVector::IsEmpty()
- {
- MutexLockRead lock(m_Mutex, m_hAllocator->UseMutex());
- return m_Blocks.empty();
- }
- HRESULT BlockVector::Allocate(
- UINT64 size,
- UINT64 alignment,
- const ALLOCATION_DESC& allocDesc,
- size_t allocationCount,
- Allocation** pAllocations)
- {
- size_t allocIndex;
- HRESULT hr = S_OK;
- {
- MutexLockWrite lock(m_Mutex, m_hAllocator->UseMutex());
- for (allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
- {
- hr = AllocatePage(
- size,
- alignment,
- allocDesc,
- pAllocations + allocIndex);
- if (FAILED(hr))
- {
- break;
- }
- }
- }
- if (FAILED(hr))
- {
- // Free all already created allocations.
- while (allocIndex--)
- {
- Free(pAllocations[allocIndex]);
- }
- ZeroMemory(pAllocations, sizeof(Allocation*) * allocationCount);
- }
- return hr;
- }
- void BlockVector::Free(Allocation* hAllocation)
- {
- NormalBlock* pBlockToDelete = NULL;
- bool budgetExceeded = false;
- if (IsHeapTypeStandard(m_HeapProps.Type))
- {
- Budget budget = {};
- m_hAllocator->GetBudgetForHeapType(budget, m_HeapProps.Type);
- budgetExceeded = budget.UsageBytes >= budget.BudgetBytes;
- }
- // Scope for lock.
- {
- MutexLockWrite lock(m_Mutex, m_hAllocator->UseMutex());
- NormalBlock* pBlock = hAllocation->m_Placed.block;
- pBlock->m_pMetadata->Free(hAllocation->GetAllocHandle());
- D3D12MA_HEAVY_ASSERT(pBlock->Validate());
- const size_t blockCount = m_Blocks.size();
- // pBlock became empty after this deallocation.
- if (pBlock->m_pMetadata->IsEmpty())
- {
- // Already has empty Allocation. We don't want to have two, so delete this one.
- if ((m_HasEmptyBlock || budgetExceeded) &&
- blockCount > m_MinBlockCount)
- {
- pBlockToDelete = pBlock;
- Remove(pBlock);
- }
- // We now have first empty block.
- else
- {
- m_HasEmptyBlock = true;
- }
- }
- // pBlock didn't become empty, but we have another empty block - find and free that one.
- // (This is optional, heuristics.)
- else if (m_HasEmptyBlock && blockCount > m_MinBlockCount)
- {
- NormalBlock* pLastBlock = m_Blocks.back();
- if (pLastBlock->m_pMetadata->IsEmpty())
- {
- pBlockToDelete = pLastBlock;
- m_Blocks.pop_back();
- m_HasEmptyBlock = false;
- }
- }
- IncrementallySortBlocks();
- }
- // Destruction of a free Allocation. Deferred until this point, outside of mutex
- // lock, for performance reason.
- if (pBlockToDelete != NULL)
- {
- D3D12MA_DELETE(m_hAllocator->GetAllocs(), pBlockToDelete);
- }
- }
- HRESULT BlockVector::CreateResource(
- UINT64 size,
- UINT64 alignment,
- const ALLOCATION_DESC& allocDesc,
- const CREATE_RESOURCE_PARAMS& createParams,
- Allocation** ppAllocation,
- REFIID riidResource,
- void** ppvResource)
- {
- HRESULT hr = Allocate(size, alignment, allocDesc, 1, ppAllocation);
- if (SUCCEEDED(hr))
- {
- ID3D12Resource* res = NULL;
- hr = m_hAllocator->CreatePlacedResourceWrap(
- (*ppAllocation)->m_Placed.block->GetHeap(),
- (*ppAllocation)->GetOffset(),
- createParams,
- D3D12MA_IID_PPV_ARGS(&res));
- if (SUCCEEDED(hr))
- {
- if (ppvResource != NULL)
- {
- hr = res->QueryInterface(riidResource, ppvResource);
- }
- if (SUCCEEDED(hr))
- {
- (*ppAllocation)->SetResourcePointer(res, createParams.GetBaseResourceDesc());
- }
- else
- {
- res->Release();
- SAFE_RELEASE(*ppAllocation);
- }
- }
- else
- {
- SAFE_RELEASE(*ppAllocation);
- }
- }
- return hr;
- }
- void BlockVector::AddStatistics(Statistics& inoutStats)
- {
- MutexLockRead lock(m_Mutex, m_hAllocator->UseMutex());
- for (size_t i = 0; i < m_Blocks.size(); ++i)
- {
- const NormalBlock* const pBlock = m_Blocks[i];
- D3D12MA_ASSERT(pBlock);
- D3D12MA_HEAVY_ASSERT(pBlock->Validate());
- pBlock->m_pMetadata->AddStatistics(inoutStats);
- }
- }
- void BlockVector::AddDetailedStatistics(DetailedStatistics& inoutStats)
- {
- MutexLockRead lock(m_Mutex, m_hAllocator->UseMutex());
- for (size_t i = 0; i < m_Blocks.size(); ++i)
- {
- const NormalBlock* const pBlock = m_Blocks[i];
- D3D12MA_ASSERT(pBlock);
- D3D12MA_HEAVY_ASSERT(pBlock->Validate());
- pBlock->m_pMetadata->AddDetailedStatistics(inoutStats);
- }
- }
- void BlockVector::WriteBlockInfoToJson(JsonWriter& json)
- {
- MutexLockRead lock(m_Mutex, m_hAllocator->UseMutex());
- json.BeginObject();
- for (size_t i = 0, count = m_Blocks.size(); i < count; ++i)
- {
- const NormalBlock* const pBlock = m_Blocks[i];
- D3D12MA_ASSERT(pBlock);
- D3D12MA_HEAVY_ASSERT(pBlock->Validate());
- json.BeginString();
- json.ContinueString(pBlock->GetId());
- json.EndString();
- json.BeginObject();
- pBlock->m_pMetadata->WriteAllocationInfoToJson(json);
- json.EndObject();
- }
- json.EndObject();
- }
- UINT64 BlockVector::CalcSumBlockSize() const
- {
- UINT64 result = 0;
- for (size_t i = m_Blocks.size(); i--; )
- {
- result += m_Blocks[i]->m_pMetadata->GetSize();
- }
- return result;
- }
- UINT64 BlockVector::CalcMaxBlockSize() const
- {
- UINT64 result = 0;
- for (size_t i = m_Blocks.size(); i--; )
- {
- result = D3D12MA_MAX(result, m_Blocks[i]->m_pMetadata->GetSize());
- if (result >= m_PreferredBlockSize)
- {
- break;
- }
- }
- return result;
- }
- void BlockVector::Remove(NormalBlock* pBlock)
- {
- for (size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
- {
- if (m_Blocks[blockIndex] == pBlock)
- {
- m_Blocks.remove(blockIndex);
- return;
- }
- }
- D3D12MA_ASSERT(0);
- }
- void BlockVector::IncrementallySortBlocks()
- {
- if (!m_IncrementalSort)
- return;
- // Bubble sort only until first swap.
- for (size_t i = 1; i < m_Blocks.size(); ++i)
- {
- if (m_Blocks[i - 1]->m_pMetadata->GetSumFreeSize() > m_Blocks[i]->m_pMetadata->GetSumFreeSize())
- {
- D3D12MA_SWAP(m_Blocks[i - 1], m_Blocks[i]);
- return;
- }
- }
- }
- void BlockVector::SortByFreeSize()
- {
- D3D12MA_SORT(m_Blocks.begin(), m_Blocks.end(),
- [](auto* b1, auto* b2)
- {
- return b1->m_pMetadata->GetSumFreeSize() < b2->m_pMetadata->GetSumFreeSize();
- });
- }
- HRESULT BlockVector::AllocatePage(
- UINT64 size,
- UINT64 alignment,
- const ALLOCATION_DESC& allocDesc,
- Allocation** pAllocation)
- {
- // Early reject: requested allocation size is larger that maximum block size for this block vector.
- if (size + D3D12MA_DEBUG_MARGIN > m_PreferredBlockSize)
- {
- return E_OUTOFMEMORY;
- }
- UINT64 freeMemory = UINT64_MAX;
- if (IsHeapTypeStandard(m_HeapProps.Type))
- {
- Budget budget = {};
- m_hAllocator->GetBudgetForHeapType(budget, m_HeapProps.Type);
- freeMemory = (budget.UsageBytes < budget.BudgetBytes) ? (budget.BudgetBytes - budget.UsageBytes) : 0;
- }
- const bool canCreateNewBlock =
- ((allocDesc.Flags & ALLOCATION_FLAG_NEVER_ALLOCATE) == 0) &&
- (m_Blocks.size() < m_MaxBlockCount) &&
- // Even if we don't have to stay within budget with this allocation, when the
- // budget would be exceeded, we don't want to allocate new blocks, but always
- // create resources as committed.
- freeMemory >= size;
- // 1. Search existing allocations
- {
- // Forward order in m_Blocks - prefer blocks with smallest amount of free space.
- for (size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
- {
- NormalBlock* const pCurrBlock = m_Blocks[blockIndex];
- D3D12MA_ASSERT(pCurrBlock);
- HRESULT hr = AllocateFromBlock(
- pCurrBlock,
- size,
- alignment,
- allocDesc.Flags,
- allocDesc.pPrivateData,
- allocDesc.Flags & ALLOCATION_FLAG_STRATEGY_MASK,
- pAllocation);
- if (SUCCEEDED(hr))
- {
- return hr;
- }
- }
- }
- // 2. Try to create new block.
- if (canCreateNewBlock)
- {
- // Calculate optimal size for new block.
- UINT64 newBlockSize = m_PreferredBlockSize;
- UINT newBlockSizeShift = 0;
- if (!m_ExplicitBlockSize)
- {
- // Allocate 1/8, 1/4, 1/2 as first blocks.
- const UINT64 maxExistingBlockSize = CalcMaxBlockSize();
- for (UINT i = 0; i < NEW_BLOCK_SIZE_SHIFT_MAX; ++i)
- {
- const UINT64 smallerNewBlockSize = newBlockSize / 2;
- if (smallerNewBlockSize > maxExistingBlockSize && smallerNewBlockSize >= size * 2)
- {
- newBlockSize = smallerNewBlockSize;
- ++newBlockSizeShift;
- }
- else
- {
- break;
- }
- }
- }
- size_t newBlockIndex = 0;
- HRESULT hr = newBlockSize <= freeMemory ?
- CreateBlock(newBlockSize, &newBlockIndex) : E_OUTOFMEMORY;
- // Allocation of this size failed? Try 1/2, 1/4, 1/8 of m_PreferredBlockSize.
- if (!m_ExplicitBlockSize)
- {
- while (FAILED(hr) && newBlockSizeShift < NEW_BLOCK_SIZE_SHIFT_MAX)
- {
- const UINT64 smallerNewBlockSize = newBlockSize / 2;
- if (smallerNewBlockSize >= size)
- {
- newBlockSize = smallerNewBlockSize;
- ++newBlockSizeShift;
- hr = newBlockSize <= freeMemory ?
- CreateBlock(newBlockSize, &newBlockIndex) : E_OUTOFMEMORY;
- }
- else
- {
- break;
- }
- }
- }
- if (SUCCEEDED(hr))
- {
- NormalBlock* const pBlock = m_Blocks[newBlockIndex];
- D3D12MA_ASSERT(pBlock->m_pMetadata->GetSize() >= size);
- hr = AllocateFromBlock(
- pBlock,
- size,
- alignment,
- allocDesc.Flags,
- allocDesc.pPrivateData,
- allocDesc.Flags & ALLOCATION_FLAG_STRATEGY_MASK,
- pAllocation);
- if (SUCCEEDED(hr))
- {
- return hr;
- }
- else
- {
- // Allocation from new block failed, possibly due to D3D12MA_DEBUG_MARGIN or alignment.
- return E_OUTOFMEMORY;
- }
- }
- }
- return E_OUTOFMEMORY;
- }
- HRESULT BlockVector::AllocateFromBlock(
- NormalBlock* pBlock,
- UINT64 size,
- UINT64 alignment,
- ALLOCATION_FLAGS allocFlags,
- void* pPrivateData,
- UINT32 strategy,
- Allocation** pAllocation)
- {
- alignment = D3D12MA_MAX(alignment, m_MinAllocationAlignment);
- AllocationRequest currRequest = {};
- if (pBlock->m_pMetadata->CreateAllocationRequest(
- size,
- alignment,
- allocFlags & ALLOCATION_FLAG_UPPER_ADDRESS,
- strategy,
- &currRequest))
- {
- return CommitAllocationRequest(currRequest, pBlock, size, alignment, pPrivateData, pAllocation);
- }
- return E_OUTOFMEMORY;
- }
- HRESULT BlockVector::CommitAllocationRequest(
- AllocationRequest& allocRequest,
- NormalBlock* pBlock,
- UINT64 size,
- UINT64 alignment,
- void* pPrivateData,
- Allocation** pAllocation)
- {
- // We no longer have an empty Allocation.
- if (pBlock->m_pMetadata->IsEmpty())
- m_HasEmptyBlock = false;
- *pAllocation = m_hAllocator->GetAllocationObjectAllocator().Allocate(m_hAllocator, size, alignment, allocRequest.zeroInitialized);
- pBlock->m_pMetadata->Alloc(allocRequest, size, *pAllocation);
- (*pAllocation)->InitPlaced(allocRequest.allocHandle, pBlock);
- (*pAllocation)->SetPrivateData(pPrivateData);
- D3D12MA_HEAVY_ASSERT(pBlock->Validate());
- m_hAllocator->m_Budget.AddAllocation(m_hAllocator->HeapPropertiesToMemorySegmentGroup(m_HeapProps), size);
- return S_OK;
- }
- HRESULT BlockVector::CreateBlock(
- UINT64 blockSize,
- size_t* pNewBlockIndex)
- {
- NormalBlock* const pBlock = D3D12MA_NEW(m_hAllocator->GetAllocs(), NormalBlock)(
- m_hAllocator,
- this,
- m_HeapProps,
- m_HeapFlags,
- blockSize,
- m_NextBlockId++);
- HRESULT hr = pBlock->Init(m_Algorithm, m_ProtectedSession, m_DenyMsaaTextures);
- if (FAILED(hr))
- {
- D3D12MA_DELETE(m_hAllocator->GetAllocs(), pBlock);
- return hr;
- }
- m_hAllocator->SetResidencyPriority(pBlock->GetHeap(), m_ResidencyPriority);
- m_Blocks.push_back(pBlock);
- if (pNewBlockIndex != NULL)
- {
- *pNewBlockIndex = m_Blocks.size() - 1;
- }
- return hr;
- }
- #endif // _D3D12MA_BLOCK_VECTOR_FUNCTIONS
- #ifndef _D3D12MA_DEFRAGMENTATION_CONTEXT_PIMPL_FUNCTIONS
- DefragmentationContextPimpl::DefragmentationContextPimpl(
- AllocatorPimpl* hAllocator,
- const DEFRAGMENTATION_DESC& desc,
- BlockVector* poolVector)
- : m_MaxPassBytes(desc.MaxBytesPerPass == 0 ? UINT64_MAX : desc.MaxBytesPerPass),
- m_MaxPassAllocations(desc.MaxAllocationsPerPass == 0 ? UINT32_MAX : desc.MaxAllocationsPerPass),
- m_Moves(hAllocator->GetAllocs())
- {
- m_Algorithm = desc.Flags & DEFRAGMENTATION_FLAG_ALGORITHM_MASK;
- if (poolVector != NULL)
- {
- m_BlockVectorCount = 1;
- m_PoolBlockVector = poolVector;
- m_pBlockVectors = &m_PoolBlockVector;
- m_PoolBlockVector->SetIncrementalSort(false);
- m_PoolBlockVector->SortByFreeSize();
- }
- else
- {
- m_BlockVectorCount = hAllocator->GetDefaultPoolCount();
- m_PoolBlockVector = NULL;
- m_pBlockVectors = hAllocator->GetDefaultPools();
- for (UINT32 i = 0; i < m_BlockVectorCount; ++i)
- {
- BlockVector* vector = m_pBlockVectors[i];
- if (vector != NULL)
- {
- vector->SetIncrementalSort(false);
- vector->SortByFreeSize();
- }
- }
- }
- switch (m_Algorithm)
- {
- case 0: // Default algorithm
- m_Algorithm = DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED;
- case DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED:
- {
- m_AlgorithmState = D3D12MA_NEW_ARRAY(hAllocator->GetAllocs(), StateBalanced, m_BlockVectorCount);
- break;
- }
- }
- }
- DefragmentationContextPimpl::~DefragmentationContextPimpl()
- {
- if (m_PoolBlockVector != NULL)
- m_PoolBlockVector->SetIncrementalSort(true);
- else
- {
- for (UINT32 i = 0; i < m_BlockVectorCount; ++i)
- {
- BlockVector* vector = m_pBlockVectors[i];
- if (vector != NULL)
- vector->SetIncrementalSort(true);
- }
- }
- if (m_AlgorithmState)
- {
- switch (m_Algorithm)
- {
- case DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED:
- D3D12MA_DELETE_ARRAY(m_Moves.GetAllocs(), reinterpret_cast<StateBalanced*>(m_AlgorithmState), m_BlockVectorCount);
- break;
- default:
- D3D12MA_ASSERT(0);
- }
- }
- }
- HRESULT DefragmentationContextPimpl::DefragmentPassBegin(DEFRAGMENTATION_PASS_MOVE_INFO& moveInfo)
- {
- if (m_PoolBlockVector != NULL)
- {
- MutexLockWrite lock(m_PoolBlockVector->GetMutex(), m_PoolBlockVector->m_hAllocator->UseMutex());
- if (m_PoolBlockVector->GetBlockCount() > 1)
- ComputeDefragmentation(*m_PoolBlockVector, 0);
- else if (m_PoolBlockVector->GetBlockCount() == 1)
- ReallocWithinBlock(*m_PoolBlockVector, m_PoolBlockVector->GetBlock(0));
- // Setup index into block vector
- for (size_t i = 0; i < m_Moves.size(); ++i)
- m_Moves[i].pDstTmpAllocation->SetPrivateData(0);
- }
- else
- {
- for (UINT32 i = 0; i < m_BlockVectorCount; ++i)
- {
- if (m_pBlockVectors[i] != NULL)
- {
- MutexLockWrite lock(m_pBlockVectors[i]->GetMutex(), m_pBlockVectors[i]->m_hAllocator->UseMutex());
- bool end = false;
- size_t movesOffset = m_Moves.size();
- if (m_pBlockVectors[i]->GetBlockCount() > 1)
- {
- end = ComputeDefragmentation(*m_pBlockVectors[i], i);
- }
- else if (m_pBlockVectors[i]->GetBlockCount() == 1)
- {
- end = ReallocWithinBlock(*m_pBlockVectors[i], m_pBlockVectors[i]->GetBlock(0));
- }
- // Setup index into block vector
- for (; movesOffset < m_Moves.size(); ++movesOffset)
- m_Moves[movesOffset].pDstTmpAllocation->SetPrivateData(reinterpret_cast<void*>(static_cast<uintptr_t>(i)));
- if (end)
- break;
- }
- }
- }
- moveInfo.MoveCount = static_cast<UINT32>(m_Moves.size());
- if (moveInfo.MoveCount > 0)
- {
- moveInfo.pMoves = m_Moves.data();
- return S_FALSE;
- }
- moveInfo.pMoves = NULL;
- return S_OK;
- }
- HRESULT DefragmentationContextPimpl::DefragmentPassEnd(DEFRAGMENTATION_PASS_MOVE_INFO& moveInfo)
- {
- D3D12MA_ASSERT(moveInfo.MoveCount > 0 ? moveInfo.pMoves != NULL : true);
- HRESULT result = S_OK;
- Vector<FragmentedBlock> immovableBlocks(m_Moves.GetAllocs());
- for (uint32_t i = 0; i < moveInfo.MoveCount; ++i)
- {
- DEFRAGMENTATION_MOVE& move = moveInfo.pMoves[i];
- size_t prevCount = 0, currentCount = 0;
- UINT64 freedBlockSize = 0;
- UINT32 vectorIndex;
- BlockVector* vector;
- if (m_PoolBlockVector != NULL)
- {
- vectorIndex = 0;
- vector = m_PoolBlockVector;
- }
- else
- {
- vectorIndex = static_cast<UINT32>(reinterpret_cast<uintptr_t>(move.pDstTmpAllocation->GetPrivateData()));
- vector = m_pBlockVectors[vectorIndex];
- D3D12MA_ASSERT(vector != NULL);
- }
- switch (move.Operation)
- {
- case DEFRAGMENTATION_MOVE_OPERATION_COPY:
- {
- move.pSrcAllocation->SwapBlockAllocation(move.pDstTmpAllocation);
- // Scope for locks, Free have it's own lock
- {
- MutexLockRead lock(vector->GetMutex(), vector->m_hAllocator->UseMutex());
- prevCount = vector->GetBlockCount();
- freedBlockSize = move.pDstTmpAllocation->GetBlock()->m_pMetadata->GetSize();
- }
- move.pDstTmpAllocation->Release();
- {
- MutexLockRead lock(vector->GetMutex(), vector->m_hAllocator->UseMutex());
- currentCount = vector->GetBlockCount();
- }
- result = S_FALSE;
- break;
- }
- case DEFRAGMENTATION_MOVE_OPERATION_IGNORE:
- {
- m_PassStats.BytesMoved -= move.pSrcAllocation->GetSize();
- --m_PassStats.AllocationsMoved;
- move.pDstTmpAllocation->Release();
- NormalBlock* newBlock = move.pSrcAllocation->GetBlock();
- bool notPresent = true;
- for (const FragmentedBlock& block : immovableBlocks)
- {
- if (block.block == newBlock)
- {
- notPresent = false;
- break;
- }
- }
- if (notPresent)
- immovableBlocks.push_back({ vectorIndex, newBlock });
- break;
- }
- case DEFRAGMENTATION_MOVE_OPERATION_DESTROY:
- {
- m_PassStats.BytesMoved -= move.pSrcAllocation->GetSize();
- --m_PassStats.AllocationsMoved;
- // Scope for locks, Free have it's own lock
- {
- MutexLockRead lock(vector->GetMutex(), vector->m_hAllocator->UseMutex());
- prevCount = vector->GetBlockCount();
- freedBlockSize = move.pSrcAllocation->GetBlock()->m_pMetadata->GetSize();
- }
- move.pSrcAllocation->Release();
- {
- MutexLockRead lock(vector->GetMutex(), vector->m_hAllocator->UseMutex());
- currentCount = vector->GetBlockCount();
- }
- freedBlockSize *= prevCount - currentCount;
- UINT64 dstBlockSize;
- {
- MutexLockRead lock(vector->GetMutex(), vector->m_hAllocator->UseMutex());
- dstBlockSize = move.pDstTmpAllocation->GetBlock()->m_pMetadata->GetSize();
- }
- move.pDstTmpAllocation->Release();
- {
- MutexLockRead lock(vector->GetMutex(), vector->m_hAllocator->UseMutex());
- freedBlockSize += dstBlockSize * (currentCount - vector->GetBlockCount());
- currentCount = vector->GetBlockCount();
- }
- result = S_FALSE;
- break;
- }
- default:
- D3D12MA_ASSERT(0);
- }
- if (prevCount > currentCount)
- {
- size_t freedBlocks = prevCount - currentCount;
- m_PassStats.HeapsFreed += static_cast<UINT32>(freedBlocks);
- m_PassStats.BytesFreed += freedBlockSize;
- }
- }
- moveInfo.MoveCount = 0;
- moveInfo.pMoves = NULL;
- m_Moves.clear();
- // Update stats
- m_GlobalStats.AllocationsMoved += m_PassStats.AllocationsMoved;
- m_GlobalStats.BytesFreed += m_PassStats.BytesFreed;
- m_GlobalStats.BytesMoved += m_PassStats.BytesMoved;
- m_GlobalStats.HeapsFreed += m_PassStats.HeapsFreed;
- m_PassStats = { 0 };
- // Move blocks with immovable allocations according to algorithm
- if (immovableBlocks.size() > 0)
- {
- // Move to the begining
- for (const FragmentedBlock& block : immovableBlocks)
- {
- BlockVector* vector = m_pBlockVectors[block.data];
- MutexLockWrite lock(vector->GetMutex(), vector->m_hAllocator->UseMutex());
- for (size_t i = m_ImmovableBlockCount; i < vector->GetBlockCount(); ++i)
- {
- if (vector->GetBlock(i) == block.block)
- {
- D3D12MA_SWAP(vector->m_Blocks[i], vector->m_Blocks[m_ImmovableBlockCount++]);
- break;
- }
- }
- }
- }
- return result;
- }
- bool DefragmentationContextPimpl::ComputeDefragmentation(BlockVector& vector, size_t index)
- {
- switch (m_Algorithm)
- {
- case DEFRAGMENTATION_FLAG_ALGORITHM_FAST:
- return ComputeDefragmentation_Fast(vector);
- default:
- D3D12MA_ASSERT(0);
- case DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED:
- return ComputeDefragmentation_Balanced(vector, index, true);
- case DEFRAGMENTATION_FLAG_ALGORITHM_FULL:
- return ComputeDefragmentation_Full(vector);
- }
- }
- DefragmentationContextPimpl::MoveAllocationData DefragmentationContextPimpl::GetMoveData(
- AllocHandle handle, BlockMetadata* metadata)
- {
- MoveAllocationData moveData;
- moveData.move.pSrcAllocation = (Allocation*)metadata->GetAllocationPrivateData(handle);
- moveData.size = moveData.move.pSrcAllocation->GetSize();
- moveData.alignment = moveData.move.pSrcAllocation->GetAlignment();
- moveData.flags = ALLOCATION_FLAG_NONE;
- return moveData;
- }
- DefragmentationContextPimpl::CounterStatus DefragmentationContextPimpl::CheckCounters(UINT64 bytes)
- {
- // Ignore allocation if will exceed max size for copy
- if (m_PassStats.BytesMoved + bytes > m_MaxPassBytes)
- {
- if (++m_IgnoredAllocs < MAX_ALLOCS_TO_IGNORE)
- return CounterStatus::Ignore;
- else
- return CounterStatus::End;
- }
- return CounterStatus::Pass;
- }
- bool DefragmentationContextPimpl::IncrementCounters(UINT64 bytes)
- {
- m_PassStats.BytesMoved += bytes;
- // Early return when max found
- if (++m_PassStats.AllocationsMoved >= m_MaxPassAllocations || m_PassStats.BytesMoved >= m_MaxPassBytes)
- {
- D3D12MA_ASSERT((m_PassStats.AllocationsMoved == m_MaxPassAllocations ||
- m_PassStats.BytesMoved == m_MaxPassBytes) && "Exceeded maximal pass threshold!");
- return true;
- }
- return false;
- }
- bool DefragmentationContextPimpl::ReallocWithinBlock(BlockVector& vector, NormalBlock* block)
- {
- BlockMetadata* metadata = block->m_pMetadata;
- for (AllocHandle handle = metadata->GetAllocationListBegin();
- handle != (AllocHandle)0;
- handle = metadata->GetNextAllocation(handle))
- {
- MoveAllocationData moveData = GetMoveData(handle, metadata);
- // Ignore newly created allocations by defragmentation algorithm
- if (moveData.move.pSrcAllocation->GetPrivateData() == this)
- continue;
- switch (CheckCounters(moveData.move.pSrcAllocation->GetSize()))
- {
- case CounterStatus::Ignore:
- continue;
- case CounterStatus::End:
- return true;
- default:
- D3D12MA_ASSERT(0);
- case CounterStatus::Pass:
- break;
- }
-
- UINT64 offset = moveData.move.pSrcAllocation->GetOffset();
- if (offset != 0 && metadata->GetSumFreeSize() >= moveData.size)
- {
- AllocationRequest request = {};
- if (metadata->CreateAllocationRequest(
- moveData.size,
- moveData.alignment,
- false,
- ALLOCATION_FLAG_STRATEGY_MIN_OFFSET,
- &request))
- {
- if (metadata->GetAllocationOffset(request.allocHandle) < offset)
- {
- if (SUCCEEDED(vector.CommitAllocationRequest(
- request,
- block,
- moveData.size,
- moveData.alignment,
- this,
- &moveData.move.pDstTmpAllocation)))
- {
- m_Moves.push_back(moveData.move);
- if (IncrementCounters(moveData.size))
- return true;
- }
- }
- }
- }
- }
- return false;
- }
- bool DefragmentationContextPimpl::AllocInOtherBlock(size_t start, size_t end, MoveAllocationData& data, BlockVector& vector)
- {
- for (; start < end; ++start)
- {
- NormalBlock* dstBlock = vector.GetBlock(start);
- if (dstBlock->m_pMetadata->GetSumFreeSize() >= data.size)
- {
- if (SUCCEEDED(vector.AllocateFromBlock(dstBlock,
- data.size,
- data.alignment,
- data.flags,
- this,
- 0,
- &data.move.pDstTmpAllocation)))
- {
- m_Moves.push_back(data.move);
- if (IncrementCounters(data.size))
- return true;
- break;
- }
- }
- }
- return false;
- }
- bool DefragmentationContextPimpl::ComputeDefragmentation_Fast(BlockVector& vector)
- {
- // Move only between blocks
- // Go through allocations in last blocks and try to fit them inside first ones
- for (size_t i = vector.GetBlockCount() - 1; i > m_ImmovableBlockCount; --i)
- {
- BlockMetadata* metadata = vector.GetBlock(i)->m_pMetadata;
- for (AllocHandle handle = metadata->GetAllocationListBegin();
- handle != (AllocHandle)0;
- handle = metadata->GetNextAllocation(handle))
- {
- MoveAllocationData moveData = GetMoveData(handle, metadata);
- // Ignore newly created allocations by defragmentation algorithm
- if (moveData.move.pSrcAllocation->GetPrivateData() == this)
- continue;
- switch (CheckCounters(moveData.move.pSrcAllocation->GetSize()))
- {
- case CounterStatus::Ignore:
- continue;
- case CounterStatus::End:
- return true;
- default:
- D3D12MA_ASSERT(0);
- case CounterStatus::Pass:
- break;
- }
- // Check all previous blocks for free space
- if (AllocInOtherBlock(0, i, moveData, vector))
- return true;
- }
- }
- return false;
- }
- bool DefragmentationContextPimpl::ComputeDefragmentation_Balanced(BlockVector& vector, size_t index, bool update)
- {
- // Go over every allocation and try to fit it in previous blocks at lowest offsets,
- // if not possible: realloc within single block to minimize offset (exclude offset == 0),
- // but only if there are noticable gaps between them (some heuristic, ex. average size of allocation in block)
- D3D12MA_ASSERT(m_AlgorithmState != NULL);
- StateBalanced& vectorState = reinterpret_cast<StateBalanced*>(m_AlgorithmState)[index];
- if (update && vectorState.avgAllocSize == UINT64_MAX)
- UpdateVectorStatistics(vector, vectorState);
- const size_t startMoveCount = m_Moves.size();
- UINT64 minimalFreeRegion = vectorState.avgFreeSize / 2;
- for (size_t i = vector.GetBlockCount() - 1; i > m_ImmovableBlockCount; --i)
- {
- NormalBlock* block = vector.GetBlock(i);
- BlockMetadata* metadata = block->m_pMetadata;
- UINT64 prevFreeRegionSize = 0;
- for (AllocHandle handle = metadata->GetAllocationListBegin();
- handle != (AllocHandle)0;
- handle = metadata->GetNextAllocation(handle))
- {
- MoveAllocationData moveData = GetMoveData(handle, metadata);
- // Ignore newly created allocations by defragmentation algorithm
- if (moveData.move.pSrcAllocation->GetPrivateData() == this)
- continue;
- switch (CheckCounters(moveData.move.pSrcAllocation->GetSize()))
- {
- case CounterStatus::Ignore:
- continue;
- case CounterStatus::End:
- return true;
- default:
- D3D12MA_ASSERT(0);
- case CounterStatus::Pass:
- break;
- }
- // Check all previous blocks for free space
- const size_t prevMoveCount = m_Moves.size();
- if (AllocInOtherBlock(0, i, moveData, vector))
- return true;
- UINT64 nextFreeRegionSize = metadata->GetNextFreeRegionSize(handle);
- // If no room found then realloc within block for lower offset
- UINT64 offset = moveData.move.pSrcAllocation->GetOffset();
- if (prevMoveCount == m_Moves.size() && offset != 0 && metadata->GetSumFreeSize() >= moveData.size)
- {
- // Check if realloc will make sense
- if (prevFreeRegionSize >= minimalFreeRegion ||
- nextFreeRegionSize >= minimalFreeRegion ||
- moveData.size <= vectorState.avgFreeSize ||
- moveData.size <= vectorState.avgAllocSize)
- {
- AllocationRequest request = {};
- if (metadata->CreateAllocationRequest(
- moveData.size,
- moveData.alignment,
- false,
- ALLOCATION_FLAG_STRATEGY_MIN_OFFSET,
- &request))
- {
- if (metadata->GetAllocationOffset(request.allocHandle) < offset)
- {
- if (SUCCEEDED(vector.CommitAllocationRequest(
- request,
- block,
- moveData.size,
- moveData.alignment,
- this,
- &moveData.move.pDstTmpAllocation)))
- {
- m_Moves.push_back(moveData.move);
- if (IncrementCounters(moveData.size))
- return true;
- }
- }
- }
- }
- }
- prevFreeRegionSize = nextFreeRegionSize;
- }
- }
- // No moves perfomed, update statistics to current vector state
- if (startMoveCount == m_Moves.size() && !update)
- {
- vectorState.avgAllocSize = UINT64_MAX;
- return ComputeDefragmentation_Balanced(vector, index, false);
- }
- return false;
- }
- bool DefragmentationContextPimpl::ComputeDefragmentation_Full(BlockVector& vector)
- {
- // Go over every allocation and try to fit it in previous blocks at lowest offsets,
- // if not possible: realloc within single block to minimize offset (exclude offset == 0)
- for (size_t i = vector.GetBlockCount() - 1; i > m_ImmovableBlockCount; --i)
- {
- NormalBlock* block = vector.GetBlock(i);
- BlockMetadata* metadata = block->m_pMetadata;
- for (AllocHandle handle = metadata->GetAllocationListBegin();
- handle != (AllocHandle)0;
- handle = metadata->GetNextAllocation(handle))
- {
- MoveAllocationData moveData = GetMoveData(handle, metadata);
- // Ignore newly created allocations by defragmentation algorithm
- if (moveData.move.pSrcAllocation->GetPrivateData() == this)
- continue;
- switch (CheckCounters(moveData.move.pSrcAllocation->GetSize()))
- {
- case CounterStatus::Ignore:
- continue;
- case CounterStatus::End:
- return true;
- default:
- D3D12MA_ASSERT(0);
- case CounterStatus::Pass:
- break;
- }
- // Check all previous blocks for free space
- const size_t prevMoveCount = m_Moves.size();
- if (AllocInOtherBlock(0, i, moveData, vector))
- return true;
- // If no room found then realloc within block for lower offset
- UINT64 offset = moveData.move.pSrcAllocation->GetOffset();
- if (prevMoveCount == m_Moves.size() && offset != 0 && metadata->GetSumFreeSize() >= moveData.size)
- {
- AllocationRequest request = {};
- if (metadata->CreateAllocationRequest(
- moveData.size,
- moveData.alignment,
- false,
- ALLOCATION_FLAG_STRATEGY_MIN_OFFSET,
- &request))
- {
- if (metadata->GetAllocationOffset(request.allocHandle) < offset)
- {
- if (SUCCEEDED(vector.CommitAllocationRequest(
- request,
- block,
- moveData.size,
- moveData.alignment,
- this,
- &moveData.move.pDstTmpAllocation)))
- {
- m_Moves.push_back(moveData.move);
- if (IncrementCounters(moveData.size))
- return true;
- }
- }
- }
- }
- }
- }
- return false;
- }
- void DefragmentationContextPimpl::UpdateVectorStatistics(BlockVector& vector, StateBalanced& state)
- {
- size_t allocCount = 0;
- size_t freeCount = 0;
- state.avgFreeSize = 0;
- state.avgAllocSize = 0;
- for (size_t i = 0; i < vector.GetBlockCount(); ++i)
- {
- BlockMetadata* metadata = vector.GetBlock(i)->m_pMetadata;
- allocCount += metadata->GetAllocationCount();
- freeCount += metadata->GetFreeRegionsCount();
- state.avgFreeSize += metadata->GetSumFreeSize();
- state.avgAllocSize += metadata->GetSize();
- }
- state.avgAllocSize = (state.avgAllocSize - state.avgFreeSize) / allocCount;
- state.avgFreeSize /= freeCount;
- }
- #endif // _D3D12MA_DEFRAGMENTATION_CONTEXT_PIMPL_FUNCTIONS
- #ifndef _D3D12MA_POOL_PIMPL_FUNCTIONS
- PoolPimpl::PoolPimpl(AllocatorPimpl* allocator, const POOL_DESC& desc)
- : m_Allocator(allocator),
- m_Desc(desc),
- m_BlockVector(NULL),
- m_Name(NULL)
- {
- const bool explicitBlockSize = desc.BlockSize != 0;
- const UINT64 preferredBlockSize = explicitBlockSize ? desc.BlockSize : D3D12MA_DEFAULT_BLOCK_SIZE;
- UINT maxBlockCount = desc.MaxBlockCount != 0 ? desc.MaxBlockCount : UINT_MAX;
- #ifndef __ID3D12Device4_INTERFACE_DEFINED__
- D3D12MA_ASSERT(m_Desc.pProtectedSession == NULL);
- #endif
- m_BlockVector = D3D12MA_NEW(allocator->GetAllocs(), BlockVector)(
- allocator, desc.HeapProperties, desc.HeapFlags,
- preferredBlockSize,
- desc.MinBlockCount, maxBlockCount,
- explicitBlockSize,
- D3D12MA_MAX(desc.MinAllocationAlignment, (UINT64)D3D12MA_DEBUG_ALIGNMENT),
- (desc.Flags & POOL_FLAG_ALGORITHM_MASK) != 0,
- (desc.Flags & POOL_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED) != 0,
- desc.pProtectedSession,
- desc.ResidencyPriority);
- }
- PoolPimpl::~PoolPimpl()
- {
- D3D12MA_ASSERT(m_PrevPool == NULL && m_NextPool == NULL);
- FreeName();
- D3D12MA_DELETE(m_Allocator->GetAllocs(), m_BlockVector);
- }
- HRESULT PoolPimpl::Init()
- {
- m_CommittedAllocations.Init(m_Allocator->UseMutex(), m_Desc.HeapProperties.Type, this);
- return m_BlockVector->CreateMinBlocks();
- }
- void PoolPimpl::GetStatistics(Statistics& outStats)
- {
- ClearStatistics(outStats);
- m_BlockVector->AddStatistics(outStats);
- m_CommittedAllocations.AddStatistics(outStats);
- }
- void PoolPimpl::CalculateStatistics(DetailedStatistics& outStats)
- {
- ClearDetailedStatistics(outStats);
- AddDetailedStatistics(outStats);
- }
- void PoolPimpl::AddDetailedStatistics(DetailedStatistics& inoutStats)
- {
- m_BlockVector->AddDetailedStatistics(inoutStats);
- m_CommittedAllocations.AddDetailedStatistics(inoutStats);
- }
- void PoolPimpl::SetName(LPCWSTR Name)
- {
- FreeName();
- if (Name)
- {
- const size_t nameCharCount = wcslen(Name) + 1;
- m_Name = D3D12MA_NEW_ARRAY(m_Allocator->GetAllocs(), WCHAR, nameCharCount);
- memcpy(m_Name, Name, nameCharCount * sizeof(WCHAR));
- }
- }
- void PoolPimpl::FreeName()
- {
- if (m_Name)
- {
- const size_t nameCharCount = wcslen(m_Name) + 1;
- D3D12MA_DELETE_ARRAY(m_Allocator->GetAllocs(), m_Name, nameCharCount);
- m_Name = NULL;
- }
- }
- #endif // _D3D12MA_POOL_PIMPL_FUNCTIONS
- #ifndef _D3D12MA_PUBLIC_INTERFACE
- HRESULT CreateAllocator(const ALLOCATOR_DESC* pDesc, Allocator** ppAllocator)
- {
- if (!pDesc || !ppAllocator || !pDesc->pDevice || !pDesc->pAdapter ||
- !(pDesc->PreferredBlockSize == 0 || (pDesc->PreferredBlockSize >= 16 && pDesc->PreferredBlockSize < 0x10000000000ull)))
- {
- D3D12MA_ASSERT(0 && "Invalid arguments passed to CreateAllocator.");
- return E_INVALIDARG;
- }
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- ALLOCATION_CALLBACKS allocationCallbacks;
- SetupAllocationCallbacks(allocationCallbacks, pDesc->pAllocationCallbacks);
- *ppAllocator = D3D12MA_NEW(allocationCallbacks, Allocator)(allocationCallbacks, *pDesc);
- HRESULT hr = (*ppAllocator)->m_Pimpl->Init(*pDesc);
- if (FAILED(hr))
- {
- D3D12MA_DELETE(allocationCallbacks, *ppAllocator);
- *ppAllocator = NULL;
- }
- return hr;
- }
- HRESULT CreateVirtualBlock(const VIRTUAL_BLOCK_DESC* pDesc, VirtualBlock** ppVirtualBlock)
- {
- if (!pDesc || !ppVirtualBlock)
- {
- D3D12MA_ASSERT(0 && "Invalid arguments passed to CreateVirtualBlock.");
- return E_INVALIDARG;
- }
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- ALLOCATION_CALLBACKS allocationCallbacks;
- SetupAllocationCallbacks(allocationCallbacks, pDesc->pAllocationCallbacks);
- *ppVirtualBlock = D3D12MA_NEW(allocationCallbacks, VirtualBlock)(allocationCallbacks, *pDesc);
- return S_OK;
- }
- #ifndef _D3D12MA_IUNKNOWN_IMPL_FUNCTIONS
- HRESULT STDMETHODCALLTYPE IUnknownImpl::QueryInterface(REFIID riid, void** ppvObject)
- {
- if (ppvObject == NULL)
- return E_POINTER;
- if (riid == IID_IUnknown)
- {
- ++m_RefCount;
- *ppvObject = this;
- return S_OK;
- }
- *ppvObject = NULL;
- return E_NOINTERFACE;
- }
- ULONG STDMETHODCALLTYPE IUnknownImpl::AddRef()
- {
- return ++m_RefCount;
- }
- ULONG STDMETHODCALLTYPE IUnknownImpl::Release()
- {
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- const uint32_t newRefCount = --m_RefCount;
- if (newRefCount == 0)
- ReleaseThis();
- return newRefCount;
- }
- #endif // _D3D12MA_IUNKNOWN_IMPL_FUNCTIONS
- #ifndef _D3D12MA_ALLOCATION_FUNCTIONS
- void Allocation::PackedData::SetType(Type type)
- {
- const UINT u = (UINT)type;
- D3D12MA_ASSERT(u < (1u << 2));
- m_Type = u;
- }
- void Allocation::PackedData::SetResourceDimension(D3D12_RESOURCE_DIMENSION resourceDimension)
- {
- const UINT u = (UINT)resourceDimension;
- D3D12MA_ASSERT(u < (1u << 3));
- m_ResourceDimension = u;
- }
- void Allocation::PackedData::SetResourceFlags(D3D12_RESOURCE_FLAGS resourceFlags)
- {
- const UINT u = (UINT)resourceFlags;
- D3D12MA_ASSERT(u < (1u << 24));
- m_ResourceFlags = u;
- }
- void Allocation::PackedData::SetTextureLayout(D3D12_TEXTURE_LAYOUT textureLayout)
- {
- const UINT u = (UINT)textureLayout;
- D3D12MA_ASSERT(u < (1u << 9));
- m_TextureLayout = u;
- }
- UINT64 Allocation::GetOffset() const
- {
- switch (m_PackedData.GetType())
- {
- case TYPE_COMMITTED:
- case TYPE_HEAP:
- return 0;
- case TYPE_PLACED:
- return m_Placed.block->m_pMetadata->GetAllocationOffset(m_Placed.allocHandle);
- default:
- D3D12MA_ASSERT(0);
- return 0;
- }
- }
- void Allocation::SetResource(ID3D12Resource* pResource)
- {
- if (pResource != m_Resource)
- {
- if (m_Resource)
- m_Resource->Release();
- m_Resource = pResource;
- if (m_Resource)
- m_Resource->AddRef();
- }
- }
- ID3D12Heap* Allocation::GetHeap() const
- {
- switch (m_PackedData.GetType())
- {
- case TYPE_COMMITTED:
- return NULL;
- case TYPE_PLACED:
- return m_Placed.block->GetHeap();
- case TYPE_HEAP:
- return m_Heap.heap;
- default:
- D3D12MA_ASSERT(0);
- return 0;
- }
- }
- void Allocation::SetName(LPCWSTR Name)
- {
- FreeName();
- if (Name)
- {
- const size_t nameCharCount = wcslen(Name) + 1;
- m_Name = D3D12MA_NEW_ARRAY(m_Allocator->GetAllocs(), WCHAR, nameCharCount);
- memcpy(m_Name, Name, nameCharCount * sizeof(WCHAR));
- }
- }
- void Allocation::ReleaseThis()
- {
- if (this == NULL)
- {
- return;
- }
- SAFE_RELEASE(m_Resource);
- switch (m_PackedData.GetType())
- {
- case TYPE_COMMITTED:
- m_Allocator->FreeCommittedMemory(this);
- break;
- case TYPE_PLACED:
- m_Allocator->FreePlacedMemory(this);
- break;
- case TYPE_HEAP:
- m_Allocator->FreeHeapMemory(this);
- break;
- }
- FreeName();
- m_Allocator->GetAllocationObjectAllocator().Free(this);
- }
- Allocation::Allocation(AllocatorPimpl* allocator, UINT64 size, UINT64 alignment, BOOL wasZeroInitialized)
- : m_Allocator{ allocator },
- m_Size{ size },
- m_Alignment{ alignment },
- m_Resource{ NULL },
- m_pPrivateData{ NULL },
- m_Name{ NULL }
- {
- D3D12MA_ASSERT(allocator);
- m_PackedData.SetType(TYPE_COUNT);
- m_PackedData.SetResourceDimension(D3D12_RESOURCE_DIMENSION_UNKNOWN);
- m_PackedData.SetResourceFlags(D3D12_RESOURCE_FLAG_NONE);
- m_PackedData.SetTextureLayout(D3D12_TEXTURE_LAYOUT_UNKNOWN);
- m_PackedData.SetWasZeroInitialized(wasZeroInitialized);
- }
- void Allocation::InitCommitted(CommittedAllocationList* list)
- {
- m_PackedData.SetType(TYPE_COMMITTED);
- m_Committed.list = list;
- m_Committed.prev = NULL;
- m_Committed.next = NULL;
- }
- void Allocation::InitPlaced(AllocHandle allocHandle, NormalBlock* block)
- {
- m_PackedData.SetType(TYPE_PLACED);
- m_Placed.allocHandle = allocHandle;
- m_Placed.block = block;
- }
- void Allocation::InitHeap(CommittedAllocationList* list, ID3D12Heap* heap)
- {
- m_PackedData.SetType(TYPE_HEAP);
- m_Heap.list = list;
- m_Committed.prev = NULL;
- m_Committed.next = NULL;
- m_Heap.heap = heap;
- }
- void Allocation::SwapBlockAllocation(Allocation* allocation)
- {
- D3D12MA_ASSERT(allocation != NULL);
- D3D12MA_ASSERT(m_PackedData.GetType() == TYPE_PLACED);
- D3D12MA_ASSERT(allocation->m_PackedData.GetType() == TYPE_PLACED);
- D3D12MA_SWAP(m_Resource, allocation->m_Resource);
- m_PackedData.SetWasZeroInitialized(allocation->m_PackedData.WasZeroInitialized());
- m_Placed.block->m_pMetadata->SetAllocationPrivateData(m_Placed.allocHandle, allocation);
- D3D12MA_SWAP(m_Placed, allocation->m_Placed);
- m_Placed.block->m_pMetadata->SetAllocationPrivateData(m_Placed.allocHandle, this);
- }
- AllocHandle Allocation::GetAllocHandle() const
- {
- switch (m_PackedData.GetType())
- {
- case TYPE_COMMITTED:
- case TYPE_HEAP:
- return (AllocHandle)0;
- case TYPE_PLACED:
- return m_Placed.allocHandle;
- default:
- D3D12MA_ASSERT(0);
- return (AllocHandle)0;
- }
- }
- NormalBlock* Allocation::GetBlock()
- {
- switch (m_PackedData.GetType())
- {
- case TYPE_COMMITTED:
- case TYPE_HEAP:
- return NULL;
- case TYPE_PLACED:
- return m_Placed.block;
- default:
- D3D12MA_ASSERT(0);
- return NULL;
- }
- }
- template<typename D3D12_RESOURCE_DESC_T>
- void Allocation::SetResourcePointer(ID3D12Resource* resource, const D3D12_RESOURCE_DESC_T* pResourceDesc)
- {
- D3D12MA_ASSERT(m_Resource == NULL && pResourceDesc);
- m_Resource = resource;
- m_PackedData.SetResourceDimension(pResourceDesc->Dimension);
- m_PackedData.SetResourceFlags(pResourceDesc->Flags);
- m_PackedData.SetTextureLayout(pResourceDesc->Layout);
- }
- void Allocation::FreeName()
- {
- if (m_Name)
- {
- const size_t nameCharCount = wcslen(m_Name) + 1;
- D3D12MA_DELETE_ARRAY(m_Allocator->GetAllocs(), m_Name, nameCharCount);
- m_Name = NULL;
- }
- }
- #endif // _D3D12MA_ALLOCATION_FUNCTIONS
- #ifndef _D3D12MA_DEFRAGMENTATION_CONTEXT_FUNCTIONS
- HRESULT DefragmentationContext::BeginPass(DEFRAGMENTATION_PASS_MOVE_INFO* pPassInfo)
- {
- D3D12MA_ASSERT(pPassInfo);
- return m_Pimpl->DefragmentPassBegin(*pPassInfo);
- }
- HRESULT DefragmentationContext::EndPass(DEFRAGMENTATION_PASS_MOVE_INFO* pPassInfo)
- {
- D3D12MA_ASSERT(pPassInfo);
- return m_Pimpl->DefragmentPassEnd(*pPassInfo);
- }
- void DefragmentationContext::GetStats(DEFRAGMENTATION_STATS* pStats)
- {
- D3D12MA_ASSERT(pStats);
- m_Pimpl->GetStats(*pStats);
- }
- void DefragmentationContext::ReleaseThis()
- {
- if (this == NULL)
- {
- return;
- }
- D3D12MA_DELETE(m_Pimpl->GetAllocs(), this);
- }
- DefragmentationContext::DefragmentationContext(AllocatorPimpl* allocator,
- const DEFRAGMENTATION_DESC& desc,
- BlockVector* poolVector)
- : m_Pimpl(D3D12MA_NEW(allocator->GetAllocs(), DefragmentationContextPimpl)(allocator, desc, poolVector)) {}
- DefragmentationContext::~DefragmentationContext()
- {
- D3D12MA_DELETE(m_Pimpl->GetAllocs(), m_Pimpl);
- }
- #endif // _D3D12MA_DEFRAGMENTATION_CONTEXT_FUNCTIONS
- #ifndef _D3D12MA_POOL_FUNCTIONS
- POOL_DESC Pool::GetDesc() const
- {
- return m_Pimpl->GetDesc();
- }
- void Pool::GetStatistics(Statistics* pStats)
- {
- D3D12MA_ASSERT(pStats);
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->GetStatistics(*pStats);
- }
- void Pool::CalculateStatistics(DetailedStatistics* pStats)
- {
- D3D12MA_ASSERT(pStats);
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->CalculateStatistics(*pStats);
- }
- void Pool::SetName(LPCWSTR Name)
- {
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->SetName(Name);
- }
- LPCWSTR Pool::GetName() const
- {
- return m_Pimpl->GetName();
- }
- HRESULT Pool::BeginDefragmentation(const DEFRAGMENTATION_DESC* pDesc, DefragmentationContext** ppContext)
- {
- D3D12MA_ASSERT(pDesc && ppContext);
- // Check for support
- if (m_Pimpl->GetBlockVector()->GetAlgorithm() & POOL_FLAG_ALGORITHM_LINEAR)
- return E_NOINTERFACE;
- AllocatorPimpl* allocator = m_Pimpl->GetAllocator();
- *ppContext = D3D12MA_NEW(allocator->GetAllocs(), DefragmentationContext)(allocator, *pDesc, m_Pimpl->GetBlockVector());
- return S_OK;
- }
- void Pool::ReleaseThis()
- {
- if (this == NULL)
- {
- return;
- }
- D3D12MA_DELETE(m_Pimpl->GetAllocator()->GetAllocs(), this);
- }
- Pool::Pool(Allocator* allocator, const POOL_DESC& desc)
- : m_Pimpl(D3D12MA_NEW(allocator->m_Pimpl->GetAllocs(), PoolPimpl)(allocator->m_Pimpl, desc)) {}
- Pool::~Pool()
- {
- m_Pimpl->GetAllocator()->UnregisterPool(this, m_Pimpl->GetDesc().HeapProperties.Type);
- D3D12MA_DELETE(m_Pimpl->GetAllocator()->GetAllocs(), m_Pimpl);
- }
- #endif // _D3D12MA_POOL_FUNCTIONS
- #ifndef _D3D12MA_ALLOCATOR_FUNCTIONS
- const D3D12_FEATURE_DATA_D3D12_OPTIONS& Allocator::GetD3D12Options() const
- {
- return m_Pimpl->GetD3D12Options();
- }
- BOOL Allocator::IsUMA() const
- {
- return m_Pimpl->IsUMA();
- }
- BOOL Allocator::IsCacheCoherentUMA() const
- {
- return m_Pimpl->IsCacheCoherentUMA();
- }
- UINT64 Allocator::GetMemoryCapacity(UINT memorySegmentGroup) const
- {
- return m_Pimpl->GetMemoryCapacity(memorySegmentGroup);
- }
- HRESULT Allocator::CreateResource(
- const ALLOCATION_DESC* pAllocDesc,
- const D3D12_RESOURCE_DESC* pResourceDesc,
- D3D12_RESOURCE_STATES InitialResourceState,
- const D3D12_CLEAR_VALUE* pOptimizedClearValue,
- Allocation** ppAllocation,
- REFIID riidResource,
- void** ppvResource)
- {
- if (!pAllocDesc || !pResourceDesc || !ppAllocation)
- {
- D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::CreateResource.");
- return E_INVALIDARG;
- }
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- return m_Pimpl->CreateResource(
- pAllocDesc,
- CREATE_RESOURCE_PARAMS(pResourceDesc, InitialResourceState, pOptimizedClearValue),
- ppAllocation,
- riidResource,
- ppvResource);
- }
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- HRESULT Allocator::CreateResource2(
- const ALLOCATION_DESC* pAllocDesc,
- const D3D12_RESOURCE_DESC1* pResourceDesc,
- D3D12_RESOURCE_STATES InitialResourceState,
- const D3D12_CLEAR_VALUE* pOptimizedClearValue,
- Allocation** ppAllocation,
- REFIID riidResource,
- void** ppvResource)
- {
- if (!pAllocDesc || !pResourceDesc || !ppAllocation)
- {
- D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::CreateResource2.");
- return E_INVALIDARG;
- }
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- return m_Pimpl->CreateResource(
- pAllocDesc,
- CREATE_RESOURCE_PARAMS(pResourceDesc, InitialResourceState, pOptimizedClearValue),
- ppAllocation,
- riidResource,
- ppvResource);
- }
- #endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- #ifdef __ID3D12Device10_INTERFACE_DEFINED__
- HRESULT Allocator::CreateResource3(
- const ALLOCATION_DESC* pAllocDesc,
- const D3D12_RESOURCE_DESC1* pResourceDesc,
- D3D12_BARRIER_LAYOUT InitialLayout,
- const D3D12_CLEAR_VALUE* pOptimizedClearValue,
- UINT32 NumCastableFormats,
- DXGI_FORMAT* pCastableFormats,
- Allocation** ppAllocation,
- REFIID riidResource,
- void** ppvResource)
- {
- if (!pAllocDesc || !pResourceDesc || !ppAllocation)
- {
- D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::CreateResource3.");
- return E_INVALIDARG;
- }
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- return m_Pimpl->CreateResource(
- pAllocDesc,
- CREATE_RESOURCE_PARAMS(pResourceDesc, InitialLayout, pOptimizedClearValue, NumCastableFormats, pCastableFormats),
- ppAllocation,
- riidResource,
- ppvResource);
- }
- #endif // #ifdef __ID3D12Device10_INTERFACE_DEFINED__
- HRESULT Allocator::AllocateMemory(
- const ALLOCATION_DESC* pAllocDesc,
- const D3D12_RESOURCE_ALLOCATION_INFO* pAllocInfo,
- Allocation** ppAllocation)
- {
- if (!ValidateAllocateMemoryParameters(pAllocDesc, pAllocInfo, ppAllocation))
- {
- D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::AllocateMemory.");
- return E_INVALIDARG;
- }
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- return m_Pimpl->AllocateMemory(pAllocDesc, pAllocInfo, ppAllocation);
- }
- HRESULT Allocator::CreateAliasingResource(
- Allocation* pAllocation,
- UINT64 AllocationLocalOffset,
- const D3D12_RESOURCE_DESC* pResourceDesc,
- D3D12_RESOURCE_STATES InitialResourceState,
- const D3D12_CLEAR_VALUE* pOptimizedClearValue,
- REFIID riidResource,
- void** ppvResource)
- {
- if (!pAllocation || !pResourceDesc || !ppvResource)
- {
- D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::CreateAliasingResource.");
- return E_INVALIDARG;
- }
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- return m_Pimpl->CreateAliasingResource(
- pAllocation,
- AllocationLocalOffset,
- CREATE_RESOURCE_PARAMS(pResourceDesc, InitialResourceState, pOptimizedClearValue),
- riidResource,
- ppvResource);
- }
- #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- HRESULT Allocator::CreateAliasingResource1(
- Allocation* pAllocation,
- UINT64 AllocationLocalOffset,
- const D3D12_RESOURCE_DESC1* pResourceDesc,
- D3D12_RESOURCE_STATES InitialResourceState,
- const D3D12_CLEAR_VALUE* pOptimizedClearValue,
- REFIID riidResource,
- void** ppvResource)
- {
- if (!pAllocation || !pResourceDesc || !ppvResource)
- {
- D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::CreateAliasingResource.");
- return E_INVALIDARG;
- }
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- return m_Pimpl->CreateAliasingResource(
- pAllocation,
- AllocationLocalOffset,
- CREATE_RESOURCE_PARAMS(pResourceDesc, InitialResourceState, pOptimizedClearValue),
- riidResource,
- ppvResource);
- }
- #endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
- #ifdef __ID3D12Device10_INTERFACE_DEFINED__
- HRESULT Allocator::CreateAliasingResource2(
- Allocation* pAllocation,
- UINT64 AllocationLocalOffset,
- const D3D12_RESOURCE_DESC1* pResourceDesc,
- D3D12_BARRIER_LAYOUT InitialLayout,
- const D3D12_CLEAR_VALUE* pOptimizedClearValue,
- UINT32 NumCastableFormats,
- DXGI_FORMAT* pCastableFormats,
- REFIID riidResource,
- void** ppvResource)
- {
- if (!pAllocation || !pResourceDesc || !ppvResource)
- {
- D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::CreateAliasingResource.");
- return E_INVALIDARG;
- }
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- return m_Pimpl->CreateAliasingResource(
- pAllocation,
- AllocationLocalOffset,
- CREATE_RESOURCE_PARAMS(pResourceDesc, InitialLayout, pOptimizedClearValue, NumCastableFormats, pCastableFormats),
- riidResource,
- ppvResource);
- }
- #endif // #ifdef __ID3D12Device10_INTERFACE_DEFINED__
- HRESULT Allocator::CreatePool(
- const POOL_DESC* pPoolDesc,
- Pool** ppPool)
- {
- if (!pPoolDesc || !ppPool ||
- (pPoolDesc->MaxBlockCount > 0 && pPoolDesc->MaxBlockCount < pPoolDesc->MinBlockCount) ||
- (pPoolDesc->MinAllocationAlignment > 0 && !IsPow2(pPoolDesc->MinAllocationAlignment)))
- {
- D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::CreatePool.");
- return E_INVALIDARG;
- }
- if (!m_Pimpl->HeapFlagsFulfillResourceHeapTier(pPoolDesc->HeapFlags))
- {
- D3D12MA_ASSERT(0 && "Invalid pPoolDesc->HeapFlags passed to Allocator::CreatePool. Did you forget to handle ResourceHeapTier=1?");
- return E_INVALIDARG;
- }
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- * ppPool = D3D12MA_NEW(m_Pimpl->GetAllocs(), Pool)(this, *pPoolDesc);
- HRESULT hr = (*ppPool)->m_Pimpl->Init();
- if (SUCCEEDED(hr))
- {
- m_Pimpl->RegisterPool(*ppPool, pPoolDesc->HeapProperties.Type);
- }
- else
- {
- D3D12MA_DELETE(m_Pimpl->GetAllocs(), *ppPool);
- *ppPool = NULL;
- }
- return hr;
- }
- void Allocator::SetCurrentFrameIndex(UINT frameIndex)
- {
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->SetCurrentFrameIndex(frameIndex);
- }
- void Allocator::GetBudget(Budget* pLocalBudget, Budget* pNonLocalBudget)
- {
- if (pLocalBudget == NULL && pNonLocalBudget == NULL)
- {
- return;
- }
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->GetBudget(pLocalBudget, pNonLocalBudget);
- }
- void Allocator::CalculateStatistics(TotalStatistics* pStats)
- {
- D3D12MA_ASSERT(pStats);
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->CalculateStatistics(*pStats);
- }
- void Allocator::BuildStatsString(WCHAR** ppStatsString, BOOL DetailedMap) const
- {
- D3D12MA_ASSERT(ppStatsString);
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->BuildStatsString(ppStatsString, DetailedMap);
- }
- void Allocator::FreeStatsString(WCHAR* pStatsString) const
- {
- if (pStatsString != NULL)
- {
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->FreeStatsString(pStatsString);
- }
- }
- void Allocator::BeginDefragmentation(const DEFRAGMENTATION_DESC* pDesc, DefragmentationContext** ppContext)
- {
- D3D12MA_ASSERT(pDesc && ppContext);
- *ppContext = D3D12MA_NEW(m_Pimpl->GetAllocs(), DefragmentationContext)(m_Pimpl, *pDesc, NULL);
- }
- void Allocator::ReleaseThis()
- {
- // Copy is needed because otherwise we would call destructor and invalidate the structure with callbacks before using it to free memory.
- const ALLOCATION_CALLBACKS allocationCallbacksCopy = m_Pimpl->GetAllocs();
- D3D12MA_DELETE(allocationCallbacksCopy, this);
- }
- Allocator::Allocator(const ALLOCATION_CALLBACKS& allocationCallbacks, const ALLOCATOR_DESC& desc)
- : m_Pimpl(D3D12MA_NEW(allocationCallbacks, AllocatorPimpl)(allocationCallbacks, desc)) {}
- Allocator::~Allocator()
- {
- D3D12MA_DELETE(m_Pimpl->GetAllocs(), m_Pimpl);
- }
- #endif // _D3D12MA_ALLOCATOR_FUNCTIONS
- #ifndef _D3D12MA_VIRTUAL_BLOCK_FUNCTIONS
- BOOL VirtualBlock::IsEmpty() const
- {
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- return m_Pimpl->m_Metadata->IsEmpty() ? TRUE : FALSE;
- }
- void VirtualBlock::GetAllocationInfo(VirtualAllocation allocation, VIRTUAL_ALLOCATION_INFO* pInfo) const
- {
- D3D12MA_ASSERT(allocation.AllocHandle != (AllocHandle)0 && pInfo);
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->m_Metadata->GetAllocationInfo(allocation.AllocHandle, *pInfo);
- }
- HRESULT VirtualBlock::Allocate(const VIRTUAL_ALLOCATION_DESC* pDesc, VirtualAllocation* pAllocation, UINT64* pOffset)
- {
- if (!pDesc || !pAllocation || pDesc->Size == 0 || !IsPow2(pDesc->Alignment))
- {
- D3D12MA_ASSERT(0 && "Invalid arguments passed to VirtualBlock::Allocate.");
- return E_INVALIDARG;
- }
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- const UINT64 alignment = pDesc->Alignment != 0 ? pDesc->Alignment : 1;
- AllocationRequest allocRequest = {};
- if (m_Pimpl->m_Metadata->CreateAllocationRequest(
- pDesc->Size,
- alignment,
- pDesc->Flags & VIRTUAL_ALLOCATION_FLAG_UPPER_ADDRESS,
- pDesc->Flags & VIRTUAL_ALLOCATION_FLAG_STRATEGY_MASK,
- &allocRequest))
- {
- m_Pimpl->m_Metadata->Alloc(allocRequest, pDesc->Size, pDesc->pPrivateData);
- D3D12MA_HEAVY_ASSERT(m_Pimpl->m_Metadata->Validate());
- pAllocation->AllocHandle = allocRequest.allocHandle;
- if (pOffset)
- *pOffset = m_Pimpl->m_Metadata->GetAllocationOffset(allocRequest.allocHandle);
- return S_OK;
- }
- pAllocation->AllocHandle = (AllocHandle)0;
- if (pOffset)
- *pOffset = UINT64_MAX;
- return E_OUTOFMEMORY;
- }
- void VirtualBlock::FreeAllocation(VirtualAllocation allocation)
- {
- if (allocation.AllocHandle == (AllocHandle)0)
- return;
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->m_Metadata->Free(allocation.AllocHandle);
- D3D12MA_HEAVY_ASSERT(m_Pimpl->m_Metadata->Validate());
- }
- void VirtualBlock::Clear()
- {
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->m_Metadata->Clear();
- D3D12MA_HEAVY_ASSERT(m_Pimpl->m_Metadata->Validate());
- }
- void VirtualBlock::SetAllocationPrivateData(VirtualAllocation allocation, void* pPrivateData)
- {
- D3D12MA_ASSERT(allocation.AllocHandle != (AllocHandle)0);
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->m_Metadata->SetAllocationPrivateData(allocation.AllocHandle, pPrivateData);
- }
- void VirtualBlock::GetStatistics(Statistics* pStats) const
- {
- D3D12MA_ASSERT(pStats);
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- D3D12MA_HEAVY_ASSERT(m_Pimpl->m_Metadata->Validate());
- ClearStatistics(*pStats);
- m_Pimpl->m_Metadata->AddStatistics(*pStats);
- }
- void VirtualBlock::CalculateStatistics(DetailedStatistics* pStats) const
- {
- D3D12MA_ASSERT(pStats);
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- D3D12MA_HEAVY_ASSERT(m_Pimpl->m_Metadata->Validate());
- ClearDetailedStatistics(*pStats);
- m_Pimpl->m_Metadata->AddDetailedStatistics(*pStats);
- }
- void VirtualBlock::BuildStatsString(WCHAR** ppStatsString) const
- {
- D3D12MA_ASSERT(ppStatsString);
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- StringBuilder sb(m_Pimpl->m_AllocationCallbacks);
- {
- JsonWriter json(m_Pimpl->m_AllocationCallbacks, sb);
- D3D12MA_HEAVY_ASSERT(m_Pimpl->m_Metadata->Validate());
- json.BeginObject();
- m_Pimpl->m_Metadata->WriteAllocationInfoToJson(json);
- json.EndObject();
- } // Scope for JsonWriter
- const size_t length = sb.GetLength();
- WCHAR* result = AllocateArray<WCHAR>(m_Pimpl->m_AllocationCallbacks, length + 1);
- memcpy(result, sb.GetData(), length * sizeof(WCHAR));
- result[length] = L'\0';
- *ppStatsString = result;
- }
- void VirtualBlock::FreeStatsString(WCHAR* pStatsString) const
- {
- if (pStatsString != NULL)
- {
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- D3D12MA::Free(m_Pimpl->m_AllocationCallbacks, pStatsString);
- }
- }
- void VirtualBlock::ReleaseThis()
- {
- // Copy is needed because otherwise we would call destructor and invalidate the structure with callbacks before using it to free memory.
- const ALLOCATION_CALLBACKS allocationCallbacksCopy = m_Pimpl->m_AllocationCallbacks;
- D3D12MA_DELETE(allocationCallbacksCopy, this);
- }
- VirtualBlock::VirtualBlock(const ALLOCATION_CALLBACKS& allocationCallbacks, const VIRTUAL_BLOCK_DESC& desc)
- : m_Pimpl(D3D12MA_NEW(allocationCallbacks, VirtualBlockPimpl)(allocationCallbacks, desc)) {}
- VirtualBlock::~VirtualBlock()
- {
- // THIS IS AN IMPORTANT ASSERT!
- // Hitting it means you have some memory leak - unreleased allocations in this virtual block.
- D3D12MA_ASSERT(m_Pimpl->m_Metadata->IsEmpty() && "Some allocations were not freed before destruction of this virtual block!");
- D3D12MA_DELETE(m_Pimpl->m_AllocationCallbacks, m_Pimpl);
- }
- #endif // _D3D12MA_VIRTUAL_BLOCK_FUNCTIONS
- #endif // _D3D12MA_PUBLIC_INTERFACE
- } // namespace D3D12MA
|