| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840 |
- /*
- Simple DirectMedia Layer
- Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
- */
- #include "SDL_internal.h"
- #ifdef SDL_GPU_VULKAN
- // Needed for VK_KHR_portability_subset
- #define VK_ENABLE_BETA_EXTENSIONS
- #define VK_NO_PROTOTYPES
- #include "../../video/khronos/vulkan/vulkan.h"
- #include <SDL3/SDL_vulkan.h>
- #include "../SDL_sysgpu.h"
- #include "../../events/SDL_windowevents_c.h"
- // Global Vulkan Loader Entry Points
- static PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL;
- #define VULKAN_GLOBAL_FUNCTION(name) \
- static PFN_##name name = NULL;
- #include "SDL_gpu_vulkan_vkfuncs.h"
- typedef struct VulkanExtensions
- {
- // These extensions are required!
- // Globally supported
- Uint8 KHR_swapchain;
- // Core since 1.1, needed for negative VkViewport::height
- Uint8 KHR_maintenance1;
- // These extensions are optional!
- // Core since 1.2, but requires annoying paperwork to implement
- Uint8 KHR_driver_properties;
- // Only required for special implementations (i.e. MoltenVK)
- Uint8 KHR_portability_subset;
- // Only required to detect devices using Dozen D3D12 driver
- Uint8 MSFT_layered_driver;
- // Only required for decoding HDR ASTC textures
- Uint8 EXT_texture_compression_astc_hdr;
- } VulkanExtensions;
- // Defines
- #define SMALL_ALLOCATION_THRESHOLD 2097152 // 2 MiB
- #define SMALL_ALLOCATION_SIZE 16777216 // 16 MiB
- #define LARGE_ALLOCATION_INCREMENT 67108864 // 64 MiB
- #define MAX_UBO_SECTION_SIZE 4096 // 4 KiB
- #define DESCRIPTOR_POOL_SIZE 128
- #define WINDOW_PROPERTY_DATA "SDL_GPUVulkanWindowPropertyData"
- #define IDENTITY_SWIZZLE \
- { \
- VK_COMPONENT_SWIZZLE_IDENTITY, \
- VK_COMPONENT_SWIZZLE_IDENTITY, \
- VK_COMPONENT_SWIZZLE_IDENTITY, \
- VK_COMPONENT_SWIZZLE_IDENTITY \
- }
- // Conversions
- static VkPresentModeKHR SDLToVK_PresentMode[] = {
- VK_PRESENT_MODE_FIFO_KHR,
- VK_PRESENT_MODE_IMMEDIATE_KHR,
- VK_PRESENT_MODE_MAILBOX_KHR
- };
- static VkFormat SDLToVK_TextureFormat[] = {
- VK_FORMAT_UNDEFINED, // INVALID
- VK_FORMAT_R8_UNORM, // A8_UNORM
- VK_FORMAT_R8_UNORM, // R8_UNORM
- VK_FORMAT_R8G8_UNORM, // R8G8_UNORM
- VK_FORMAT_R8G8B8A8_UNORM, // R8G8B8A8_UNORM
- VK_FORMAT_R16_UNORM, // R16_UNORM
- VK_FORMAT_R16G16_UNORM, // R16G16_UNORM
- VK_FORMAT_R16G16B16A16_UNORM, // R16G16B16A16_UNORM
- VK_FORMAT_A2B10G10R10_UNORM_PACK32, // R10G10B10A2_UNORM
- VK_FORMAT_R5G6B5_UNORM_PACK16, // B5G6R5_UNORM
- VK_FORMAT_A1R5G5B5_UNORM_PACK16, // B5G5R5A1_UNORM
- VK_FORMAT_B4G4R4A4_UNORM_PACK16, // B4G4R4A4_UNORM
- VK_FORMAT_B8G8R8A8_UNORM, // B8G8R8A8_UNORM
- VK_FORMAT_BC1_RGBA_UNORM_BLOCK, // BC1_UNORM
- VK_FORMAT_BC2_UNORM_BLOCK, // BC2_UNORM
- VK_FORMAT_BC3_UNORM_BLOCK, // BC3_UNORM
- VK_FORMAT_BC4_UNORM_BLOCK, // BC4_UNORM
- VK_FORMAT_BC5_UNORM_BLOCK, // BC5_UNORM
- VK_FORMAT_BC7_UNORM_BLOCK, // BC7_UNORM
- VK_FORMAT_BC6H_SFLOAT_BLOCK, // BC6H_FLOAT
- VK_FORMAT_BC6H_UFLOAT_BLOCK, // BC6H_UFLOAT
- VK_FORMAT_R8_SNORM, // R8_SNORM
- VK_FORMAT_R8G8_SNORM, // R8G8_SNORM
- VK_FORMAT_R8G8B8A8_SNORM, // R8G8B8A8_SNORM
- VK_FORMAT_R16_SNORM, // R16_SNORM
- VK_FORMAT_R16G16_SNORM, // R16G16_SNORM
- VK_FORMAT_R16G16B16A16_SNORM, // R16G16B16A16_SNORM
- VK_FORMAT_R16_SFLOAT, // R16_FLOAT
- VK_FORMAT_R16G16_SFLOAT, // R16G16_FLOAT
- VK_FORMAT_R16G16B16A16_SFLOAT, // R16G16B16A16_FLOAT
- VK_FORMAT_R32_SFLOAT, // R32_FLOAT
- VK_FORMAT_R32G32_SFLOAT, // R32G32_FLOAT
- VK_FORMAT_R32G32B32A32_SFLOAT, // R32G32B32A32_FLOAT
- VK_FORMAT_B10G11R11_UFLOAT_PACK32, // R11G11B10_UFLOAT
- VK_FORMAT_R8_UINT, // R8_UINT
- VK_FORMAT_R8G8_UINT, // R8G8_UINT
- VK_FORMAT_R8G8B8A8_UINT, // R8G8B8A8_UINT
- VK_FORMAT_R16_UINT, // R16_UINT
- VK_FORMAT_R16G16_UINT, // R16G16_UINT
- VK_FORMAT_R16G16B16A16_UINT, // R16G16B16A16_UINT
- VK_FORMAT_R32_UINT, // R32_UINT
- VK_FORMAT_R32G32_UINT, // R32G32_UINT
- VK_FORMAT_R32G32B32A32_UINT, // R32G32B32A32_UINT
- VK_FORMAT_R8_SINT, // R8_INT
- VK_FORMAT_R8G8_SINT, // R8G8_INT
- VK_FORMAT_R8G8B8A8_SINT, // R8G8B8A8_INT
- VK_FORMAT_R16_SINT, // R16_INT
- VK_FORMAT_R16G16_SINT, // R16G16_INT
- VK_FORMAT_R16G16B16A16_SINT, // R16G16B16A16_INT
- VK_FORMAT_R32_SINT, // R32_INT
- VK_FORMAT_R32G32_SINT, // R32G32_INT
- VK_FORMAT_R32G32B32A32_SINT, // R32G32B32A32_INT
- VK_FORMAT_R8G8B8A8_SRGB, // R8G8B8A8_UNORM_SRGB
- VK_FORMAT_B8G8R8A8_SRGB, // B8G8R8A8_UNORM_SRGB
- VK_FORMAT_BC1_RGBA_SRGB_BLOCK, // BC1_UNORM_SRGB
- VK_FORMAT_BC2_SRGB_BLOCK, // BC3_UNORM_SRGB
- VK_FORMAT_BC3_SRGB_BLOCK, // BC3_UNORM_SRGB
- VK_FORMAT_BC7_SRGB_BLOCK, // BC7_UNORM_SRGB
- VK_FORMAT_D16_UNORM, // D16_UNORM
- VK_FORMAT_X8_D24_UNORM_PACK32, // D24_UNORM
- VK_FORMAT_D32_SFLOAT, // D32_FLOAT
- VK_FORMAT_D24_UNORM_S8_UINT, // D24_UNORM_S8_UINT
- VK_FORMAT_D32_SFLOAT_S8_UINT, // D32_FLOAT_S8_UINT
- VK_FORMAT_ASTC_4x4_UNORM_BLOCK, // ASTC_4x4_UNORM
- VK_FORMAT_ASTC_5x4_UNORM_BLOCK, // ASTC_5x4_UNORM
- VK_FORMAT_ASTC_5x5_UNORM_BLOCK, // ASTC_5x5_UNORM
- VK_FORMAT_ASTC_6x5_UNORM_BLOCK, // ASTC_6x5_UNORM
- VK_FORMAT_ASTC_6x6_UNORM_BLOCK, // ASTC_6x6_UNORM
- VK_FORMAT_ASTC_8x5_UNORM_BLOCK, // ASTC_8x5_UNORM
- VK_FORMAT_ASTC_8x6_UNORM_BLOCK, // ASTC_8x6_UNORM
- VK_FORMAT_ASTC_8x8_UNORM_BLOCK, // ASTC_8x8_UNORM
- VK_FORMAT_ASTC_10x5_UNORM_BLOCK, // ASTC_10x5_UNORM
- VK_FORMAT_ASTC_10x6_UNORM_BLOCK, // ASTC_10x6_UNORM
- VK_FORMAT_ASTC_10x8_UNORM_BLOCK, // ASTC_10x8_UNORM
- VK_FORMAT_ASTC_10x10_UNORM_BLOCK, // ASTC_10x10_UNORM
- VK_FORMAT_ASTC_12x10_UNORM_BLOCK, // ASTC_12x10_UNORM
- VK_FORMAT_ASTC_12x12_UNORM_BLOCK, // ASTC_12x12_UNORM
- VK_FORMAT_ASTC_4x4_SRGB_BLOCK, // ASTC_4x4_UNORM_SRGB
- VK_FORMAT_ASTC_5x4_SRGB_BLOCK, // ASTC_5x4_UNORM_SRGB
- VK_FORMAT_ASTC_5x5_SRGB_BLOCK, // ASTC_5x5_UNORM_SRGB
- VK_FORMAT_ASTC_6x5_SRGB_BLOCK, // ASTC_6x5_UNORM_SRGB
- VK_FORMAT_ASTC_6x6_SRGB_BLOCK, // ASTC_6x6_UNORM_SRGB
- VK_FORMAT_ASTC_8x5_SRGB_BLOCK, // ASTC_8x5_UNORM_SRGB
- VK_FORMAT_ASTC_8x6_SRGB_BLOCK, // ASTC_8x6_UNORM_SRGB
- VK_FORMAT_ASTC_8x8_SRGB_BLOCK, // ASTC_8x8_UNORM_SRGB
- VK_FORMAT_ASTC_10x5_SRGB_BLOCK, // ASTC_10x5_UNORM_SRGB
- VK_FORMAT_ASTC_10x6_SRGB_BLOCK, // ASTC_10x6_UNORM_SRGB
- VK_FORMAT_ASTC_10x8_SRGB_BLOCK, // ASTC_10x8_UNORM_SRGB
- VK_FORMAT_ASTC_10x10_SRGB_BLOCK, // ASTC_10x10_UNORM_SRGB
- VK_FORMAT_ASTC_12x10_SRGB_BLOCK, // ASTC_12x10_UNORM_SRGB
- VK_FORMAT_ASTC_12x12_SRGB_BLOCK, // ASTC_12x12_UNORM_SRGB
- VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT, // ASTC_4x4_FLOAT
- VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT, // ASTC_5x4_FLOAT
- VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT, // ASTC_5x5_FLOAT
- VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT, // ASTC_6x5_FLOAT
- VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT, // ASTC_6x6_FLOAT
- VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT, // ASTC_8x5_FLOAT
- VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT, // ASTC_8x6_FLOAT
- VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT, // ASTC_8x8_FLOAT
- VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT, // ASTC_10x5_FLOAT
- VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT, // ASTC_10x6_FLOAT
- VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT, // ASTC_10x8_FLOAT
- VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT, // ASTC_10x10_FLOAT
- VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT, // ASTC_12x10_FLOAT
- VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK // ASTC_12x12_FLOAT
- };
- SDL_COMPILE_TIME_ASSERT(SDLToVK_TextureFormat, SDL_arraysize(SDLToVK_TextureFormat) == SDL_GPU_TEXTUREFORMAT_MAX_ENUM_VALUE);
- static VkComponentMapping SwizzleForSDLFormat(SDL_GPUTextureFormat format)
- {
- if (format == SDL_GPU_TEXTUREFORMAT_A8_UNORM) {
- // TODO: use VK_FORMAT_A8_UNORM_KHR from VK_KHR_maintenance5 when available
- return (VkComponentMapping){
- VK_COMPONENT_SWIZZLE_ZERO,
- VK_COMPONENT_SWIZZLE_ZERO,
- VK_COMPONENT_SWIZZLE_ZERO,
- VK_COMPONENT_SWIZZLE_R,
- };
- }
- if (format == SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM) {
- // ARGB -> BGRA
- // TODO: use VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT from VK_EXT_4444_formats when available
- return (VkComponentMapping){
- VK_COMPONENT_SWIZZLE_G,
- VK_COMPONENT_SWIZZLE_R,
- VK_COMPONENT_SWIZZLE_A,
- VK_COMPONENT_SWIZZLE_B,
- };
- }
- return (VkComponentMapping)IDENTITY_SWIZZLE;
- }
- static VkFormat SwapchainCompositionToFormat[] = {
- VK_FORMAT_B8G8R8A8_UNORM, // SDR
- VK_FORMAT_B8G8R8A8_SRGB, // SDR_LINEAR
- VK_FORMAT_R16G16B16A16_SFLOAT, // HDR_EXTENDED_LINEAR
- VK_FORMAT_A2B10G10R10_UNORM_PACK32 // HDR10_ST2084
- };
- static VkFormat SwapchainCompositionToFallbackFormat[] = {
- VK_FORMAT_R8G8B8A8_UNORM, // SDR
- VK_FORMAT_R8G8B8A8_SRGB, // SDR_LINEAR
- VK_FORMAT_UNDEFINED, // HDR_EXTENDED_LINEAR (no fallback)
- VK_FORMAT_UNDEFINED // HDR10_ST2084 (no fallback)
- };
- static SDL_GPUTextureFormat SwapchainCompositionToSDLFormat(
- SDL_GPUSwapchainComposition composition,
- bool usingFallback)
- {
- switch (composition) {
- case SDL_GPU_SWAPCHAINCOMPOSITION_SDR:
- return usingFallback ? SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM : SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM;
- case SDL_GPU_SWAPCHAINCOMPOSITION_SDR_LINEAR:
- return usingFallback ? SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB : SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB;
- case SDL_GPU_SWAPCHAINCOMPOSITION_HDR_EXTENDED_LINEAR:
- return SDL_GPU_TEXTUREFORMAT_R16G16B16A16_FLOAT;
- case SDL_GPU_SWAPCHAINCOMPOSITION_HDR10_ST2084:
- return SDL_GPU_TEXTUREFORMAT_R10G10B10A2_UNORM;
- default:
- return SDL_GPU_TEXTUREFORMAT_INVALID;
- }
- }
- static VkColorSpaceKHR SwapchainCompositionToColorSpace[] = {
- VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, // SDR
- VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, // SDR_LINEAR
- VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT, // HDR_EXTENDED_LINEAR
- VK_COLOR_SPACE_HDR10_ST2084_EXT // HDR10_ST2084
- };
- static VkComponentMapping SwapchainCompositionSwizzle[] = {
- IDENTITY_SWIZZLE, // SDR
- IDENTITY_SWIZZLE, // SDR_LINEAR
- IDENTITY_SWIZZLE, // HDR_EXTENDED_LINEAR
- {
- // HDR10_ST2084
- VK_COMPONENT_SWIZZLE_R,
- VK_COMPONENT_SWIZZLE_G,
- VK_COMPONENT_SWIZZLE_B,
- VK_COMPONENT_SWIZZLE_A,
- }
- };
- static VkFormat SDLToVK_VertexFormat[] = {
- VK_FORMAT_UNDEFINED, // INVALID
- VK_FORMAT_R32_SINT, // INT
- VK_FORMAT_R32G32_SINT, // INT2
- VK_FORMAT_R32G32B32_SINT, // INT3
- VK_FORMAT_R32G32B32A32_SINT, // INT4
- VK_FORMAT_R32_UINT, // UINT
- VK_FORMAT_R32G32_UINT, // UINT2
- VK_FORMAT_R32G32B32_UINT, // UINT3
- VK_FORMAT_R32G32B32A32_UINT, // UINT4
- VK_FORMAT_R32_SFLOAT, // FLOAT
- VK_FORMAT_R32G32_SFLOAT, // FLOAT2
- VK_FORMAT_R32G32B32_SFLOAT, // FLOAT3
- VK_FORMAT_R32G32B32A32_SFLOAT, // FLOAT4
- VK_FORMAT_R8G8_SINT, // BYTE2
- VK_FORMAT_R8G8B8A8_SINT, // BYTE4
- VK_FORMAT_R8G8_UINT, // UBYTE2
- VK_FORMAT_R8G8B8A8_UINT, // UBYTE4
- VK_FORMAT_R8G8_SNORM, // BYTE2_NORM
- VK_FORMAT_R8G8B8A8_SNORM, // BYTE4_NORM
- VK_FORMAT_R8G8_UNORM, // UBYTE2_NORM
- VK_FORMAT_R8G8B8A8_UNORM, // UBYTE4_NORM
- VK_FORMAT_R16G16_SINT, // SHORT2
- VK_FORMAT_R16G16B16A16_SINT, // SHORT4
- VK_FORMAT_R16G16_UINT, // USHORT2
- VK_FORMAT_R16G16B16A16_UINT, // USHORT4
- VK_FORMAT_R16G16_SNORM, // SHORT2_NORM
- VK_FORMAT_R16G16B16A16_SNORM, // SHORT4_NORM
- VK_FORMAT_R16G16_UNORM, // USHORT2_NORM
- VK_FORMAT_R16G16B16A16_UNORM, // USHORT4_NORM
- VK_FORMAT_R16G16_SFLOAT, // HALF2
- VK_FORMAT_R16G16B16A16_SFLOAT // HALF4
- };
- SDL_COMPILE_TIME_ASSERT(SDLToVK_VertexFormat, SDL_arraysize(SDLToVK_VertexFormat) == SDL_GPU_VERTEXELEMENTFORMAT_MAX_ENUM_VALUE);
- static VkIndexType SDLToVK_IndexType[] = {
- VK_INDEX_TYPE_UINT16,
- VK_INDEX_TYPE_UINT32
- };
- static VkPrimitiveTopology SDLToVK_PrimitiveType[] = {
- VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
- VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
- VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
- VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
- VK_PRIMITIVE_TOPOLOGY_POINT_LIST
- };
- static VkCullModeFlags SDLToVK_CullMode[] = {
- VK_CULL_MODE_NONE,
- VK_CULL_MODE_FRONT_BIT,
- VK_CULL_MODE_BACK_BIT,
- VK_CULL_MODE_FRONT_AND_BACK
- };
- static VkFrontFace SDLToVK_FrontFace[] = {
- VK_FRONT_FACE_COUNTER_CLOCKWISE,
- VK_FRONT_FACE_CLOCKWISE
- };
- static VkBlendFactor SDLToVK_BlendFactor[] = {
- VK_BLEND_FACTOR_ZERO, // INVALID
- VK_BLEND_FACTOR_ZERO,
- VK_BLEND_FACTOR_ONE,
- VK_BLEND_FACTOR_SRC_COLOR,
- VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR,
- VK_BLEND_FACTOR_DST_COLOR,
- VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR,
- VK_BLEND_FACTOR_SRC_ALPHA,
- VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
- VK_BLEND_FACTOR_DST_ALPHA,
- VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA,
- VK_BLEND_FACTOR_CONSTANT_COLOR,
- VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
- VK_BLEND_FACTOR_SRC_ALPHA_SATURATE
- };
- SDL_COMPILE_TIME_ASSERT(SDLToVK_BlendFactor, SDL_arraysize(SDLToVK_BlendFactor) == SDL_GPU_BLENDFACTOR_MAX_ENUM_VALUE);
- static VkBlendOp SDLToVK_BlendOp[] = {
- VK_BLEND_OP_ADD, // INVALID
- VK_BLEND_OP_ADD,
- VK_BLEND_OP_SUBTRACT,
- VK_BLEND_OP_REVERSE_SUBTRACT,
- VK_BLEND_OP_MIN,
- VK_BLEND_OP_MAX
- };
- SDL_COMPILE_TIME_ASSERT(SDLToVK_BlendOp, SDL_arraysize(SDLToVK_BlendOp) == SDL_GPU_BLENDOP_MAX_ENUM_VALUE);
- static VkCompareOp SDLToVK_CompareOp[] = {
- VK_COMPARE_OP_NEVER, // INVALID
- VK_COMPARE_OP_NEVER,
- VK_COMPARE_OP_LESS,
- VK_COMPARE_OP_EQUAL,
- VK_COMPARE_OP_LESS_OR_EQUAL,
- VK_COMPARE_OP_GREATER,
- VK_COMPARE_OP_NOT_EQUAL,
- VK_COMPARE_OP_GREATER_OR_EQUAL,
- VK_COMPARE_OP_ALWAYS
- };
- SDL_COMPILE_TIME_ASSERT(SDLToVK_CompareOp, SDL_arraysize(SDLToVK_CompareOp) == SDL_GPU_COMPAREOP_MAX_ENUM_VALUE);
- static VkStencilOp SDLToVK_StencilOp[] = {
- VK_STENCIL_OP_KEEP, // INVALID
- VK_STENCIL_OP_KEEP,
- VK_STENCIL_OP_ZERO,
- VK_STENCIL_OP_REPLACE,
- VK_STENCIL_OP_INCREMENT_AND_CLAMP,
- VK_STENCIL_OP_DECREMENT_AND_CLAMP,
- VK_STENCIL_OP_INVERT,
- VK_STENCIL_OP_INCREMENT_AND_WRAP,
- VK_STENCIL_OP_DECREMENT_AND_WRAP
- };
- SDL_COMPILE_TIME_ASSERT(SDLToVK_StencilOp, SDL_arraysize(SDLToVK_StencilOp) == SDL_GPU_STENCILOP_MAX_ENUM_VALUE);
- static VkAttachmentLoadOp SDLToVK_LoadOp[] = {
- VK_ATTACHMENT_LOAD_OP_LOAD,
- VK_ATTACHMENT_LOAD_OP_CLEAR,
- VK_ATTACHMENT_LOAD_OP_DONT_CARE
- };
- static VkAttachmentStoreOp SDLToVK_StoreOp[] = {
- VK_ATTACHMENT_STORE_OP_STORE,
- VK_ATTACHMENT_STORE_OP_DONT_CARE,
- VK_ATTACHMENT_STORE_OP_DONT_CARE,
- VK_ATTACHMENT_STORE_OP_STORE
- };
- static VkSampleCountFlagBits SDLToVK_SampleCount[] = {
- VK_SAMPLE_COUNT_1_BIT,
- VK_SAMPLE_COUNT_2_BIT,
- VK_SAMPLE_COUNT_4_BIT,
- VK_SAMPLE_COUNT_8_BIT
- };
- static VkVertexInputRate SDLToVK_VertexInputRate[] = {
- VK_VERTEX_INPUT_RATE_VERTEX,
- VK_VERTEX_INPUT_RATE_INSTANCE
- };
- static VkFilter SDLToVK_Filter[] = {
- VK_FILTER_NEAREST,
- VK_FILTER_LINEAR
- };
- static VkSamplerMipmapMode SDLToVK_SamplerMipmapMode[] = {
- VK_SAMPLER_MIPMAP_MODE_NEAREST,
- VK_SAMPLER_MIPMAP_MODE_LINEAR
- };
- static VkSamplerAddressMode SDLToVK_SamplerAddressMode[] = {
- VK_SAMPLER_ADDRESS_MODE_REPEAT,
- VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT,
- VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE
- };
- // Structures
- typedef struct VulkanMemoryAllocation VulkanMemoryAllocation;
- typedef struct VulkanBuffer VulkanBuffer;
- typedef struct VulkanBufferContainer VulkanBufferContainer;
- typedef struct VulkanUniformBuffer VulkanUniformBuffer;
- typedef struct VulkanTexture VulkanTexture;
- typedef struct VulkanTextureContainer VulkanTextureContainer;
- typedef struct VulkanFenceHandle
- {
- VkFence fence;
- SDL_AtomicInt referenceCount;
- } VulkanFenceHandle;
- // Memory Allocation
- typedef struct VulkanMemoryFreeRegion
- {
- VulkanMemoryAllocation *allocation;
- VkDeviceSize offset;
- VkDeviceSize size;
- Uint32 allocationIndex;
- Uint32 sortedIndex;
- } VulkanMemoryFreeRegion;
- typedef struct VulkanMemoryUsedRegion
- {
- VulkanMemoryAllocation *allocation;
- VkDeviceSize offset;
- VkDeviceSize size;
- VkDeviceSize resourceOffset; // differs from offset based on alignment
- VkDeviceSize resourceSize; // differs from size based on alignment
- VkDeviceSize alignment;
- Uint8 isBuffer;
- union
- {
- VulkanBuffer *vulkanBuffer;
- VulkanTexture *vulkanTexture;
- };
- } VulkanMemoryUsedRegion;
- typedef struct VulkanMemorySubAllocator
- {
- Uint32 memoryTypeIndex;
- VulkanMemoryAllocation **allocations;
- Uint32 allocationCount;
- VulkanMemoryFreeRegion **sortedFreeRegions;
- Uint32 sortedFreeRegionCount;
- Uint32 sortedFreeRegionCapacity;
- } VulkanMemorySubAllocator;
- struct VulkanMemoryAllocation
- {
- VulkanMemorySubAllocator *allocator;
- VkDeviceMemory memory;
- VkDeviceSize size;
- VulkanMemoryUsedRegion **usedRegions;
- Uint32 usedRegionCount;
- Uint32 usedRegionCapacity;
- VulkanMemoryFreeRegion **freeRegions;
- Uint32 freeRegionCount;
- Uint32 freeRegionCapacity;
- Uint8 availableForAllocation;
- VkDeviceSize freeSpace;
- VkDeviceSize usedSpace;
- Uint8 *mapPointer;
- SDL_Mutex *memoryLock;
- };
- typedef struct VulkanMemoryAllocator
- {
- VulkanMemorySubAllocator subAllocators[VK_MAX_MEMORY_TYPES];
- } VulkanMemoryAllocator;
- // Memory structures
- typedef enum VulkanBufferType
- {
- VULKAN_BUFFER_TYPE_GPU,
- VULKAN_BUFFER_TYPE_UNIFORM,
- VULKAN_BUFFER_TYPE_TRANSFER
- } VulkanBufferType;
- struct VulkanBuffer
- {
- VulkanBufferContainer *container;
- Uint32 containerIndex;
- VkBuffer buffer;
- VulkanMemoryUsedRegion *usedRegion;
- // Needed for uniforms and defrag
- VulkanBufferType type;
- SDL_GPUBufferUsageFlags usage;
- VkDeviceSize size;
- SDL_AtomicInt referenceCount;
- bool transitioned;
- bool markedForDestroy; // so that defrag doesn't double-free
- VulkanUniformBuffer *uniformBufferForDefrag;
- };
- struct VulkanBufferContainer
- {
- VulkanBuffer *activeBuffer;
- VulkanBuffer **buffers;
- Uint32 bufferCapacity;
- Uint32 bufferCount;
- bool dedicated;
- char *debugName;
- };
- // Renderer Structure
- typedef struct QueueFamilyIndices
- {
- Uint32 graphicsFamily;
- Uint32 presentFamily;
- Uint32 computeFamily;
- Uint32 transferFamily;
- } QueueFamilyIndices;
- typedef struct VulkanSampler
- {
- VkSampler sampler;
- SDL_AtomicInt referenceCount;
- } VulkanSampler;
- typedef struct VulkanShader
- {
- VkShaderModule shaderModule;
- char *entrypointName;
- SDL_GPUShaderStage stage;
- Uint32 numSamplers;
- Uint32 numStorageTextures;
- Uint32 numStorageBuffers;
- Uint32 numUniformBuffers;
- SDL_AtomicInt referenceCount;
- } VulkanShader;
- /* Textures are made up of individual subresources.
- * This helps us barrier the resource efficiently.
- */
- typedef struct VulkanTextureSubresource
- {
- VulkanTexture *parent;
- Uint32 layer;
- Uint32 level;
- VkImageView *renderTargetViews; // One render target view per depth slice
- VkImageView computeWriteView;
- VkImageView depthStencilView;
- } VulkanTextureSubresource;
- struct VulkanTexture
- {
- VulkanTextureContainer *container;
- Uint32 containerIndex;
- VulkanMemoryUsedRegion *usedRegion;
- VkImage image;
- VkImageView fullView; // used for samplers and storage reads
- VkComponentMapping swizzle;
- VkImageAspectFlags aspectFlags;
- Uint32 depth; // used for cleanup only
- // FIXME: It'd be nice if we didn't have to have this on the texture...
- SDL_GPUTextureUsageFlags usage; // used for defrag transitions only.
- Uint32 subresourceCount;
- VulkanTextureSubresource *subresources;
- bool markedForDestroy; // so that defrag doesn't double-free
- SDL_AtomicInt referenceCount;
- };
- struct VulkanTextureContainer
- {
- TextureCommonHeader header;
- VulkanTexture *activeTexture;
- Uint32 textureCapacity;
- Uint32 textureCount;
- VulkanTexture **textures;
- char *debugName;
- bool canBeCycled;
- };
- typedef enum VulkanBufferUsageMode
- {
- VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE,
- VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION,
- VULKAN_BUFFER_USAGE_MODE_VERTEX_READ,
- VULKAN_BUFFER_USAGE_MODE_INDEX_READ,
- VULKAN_BUFFER_USAGE_MODE_INDIRECT,
- VULKAN_BUFFER_USAGE_MODE_GRAPHICS_STORAGE_READ,
- VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ,
- VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE,
- } VulkanBufferUsageMode;
- typedef enum VulkanTextureUsageMode
- {
- VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED,
- VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE,
- VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION,
- VULKAN_TEXTURE_USAGE_MODE_SAMPLER,
- VULKAN_TEXTURE_USAGE_MODE_GRAPHICS_STORAGE_READ,
- VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ,
- VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE,
- VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT,
- VULKAN_TEXTURE_USAGE_MODE_DEPTH_STENCIL_ATTACHMENT,
- VULKAN_TEXTURE_USAGE_MODE_PRESENT
- } VulkanTextureUsageMode;
- typedef enum VulkanUniformBufferStage
- {
- VULKAN_UNIFORM_BUFFER_STAGE_VERTEX,
- VULKAN_UNIFORM_BUFFER_STAGE_FRAGMENT,
- VULKAN_UNIFORM_BUFFER_STAGE_COMPUTE
- } VulkanUniformBufferStage;
- typedef struct VulkanFramebuffer
- {
- VkFramebuffer framebuffer;
- SDL_AtomicInt referenceCount;
- } VulkanFramebuffer;
- typedef struct WindowData
- {
- SDL_Window *window;
- SDL_GPUSwapchainComposition swapchainComposition;
- SDL_GPUPresentMode presentMode;
- bool needsSwapchainRecreate;
- bool needsSurfaceRecreate;
- Uint32 swapchainCreateWidth;
- Uint32 swapchainCreateHeight;
- // Window surface
- VkSurfaceKHR surface;
- // Swapchain for window surface
- VkSwapchainKHR swapchain;
- VkFormat format;
- VkColorSpaceKHR colorSpace;
- VkComponentMapping swapchainSwizzle;
- bool usingFallbackFormat;
- // Swapchain images
- VulkanTextureContainer *textureContainers; // use containers so that swapchain textures can use the same API as other textures
- Uint32 imageCount;
- Uint32 width;
- Uint32 height;
- // Synchronization primitives
- VkSemaphore imageAvailableSemaphore[MAX_FRAMES_IN_FLIGHT];
- VkSemaphore *renderFinishedSemaphore;
- SDL_GPUFence *inFlightFences[MAX_FRAMES_IN_FLIGHT];
- Uint32 frameCounter;
- } WindowData;
- typedef struct SwapchainSupportDetails
- {
- VkSurfaceCapabilitiesKHR capabilities;
- VkSurfaceFormatKHR *formats;
- Uint32 formatsLength;
- VkPresentModeKHR *presentModes;
- Uint32 presentModesLength;
- } SwapchainSupportDetails;
- typedef struct VulkanPresentData
- {
- WindowData *windowData;
- Uint32 swapchainImageIndex;
- } VulkanPresentData;
- struct VulkanUniformBuffer
- {
- VulkanBuffer *buffer;
- Uint32 drawOffset;
- Uint32 writeOffset;
- };
- typedef struct VulkanDescriptorInfo
- {
- VkDescriptorType descriptorType;
- VkShaderStageFlagBits stageFlag;
- } VulkanDescriptorInfo;
- typedef struct DescriptorSetPool
- {
- // It's a pool... of pools!!!
- Uint32 poolCount;
- VkDescriptorPool *descriptorPools;
- // We'll just manage the descriptor sets ourselves instead of freeing the sets
- VkDescriptorSet *descriptorSets;
- Uint32 descriptorSetCount;
- Uint32 descriptorSetIndex;
- } DescriptorSetPool;
- // A command buffer acquires a cache at command buffer acquisition time
- typedef struct DescriptorSetCache
- {
- // Pools are indexed by DescriptorSetLayoutID which increases monotonically
- // There's only a certain number of maximum layouts possible since we de-duplicate them.
- DescriptorSetPool *pools;
- Uint32 poolCount;
- } DescriptorSetCache;
- typedef struct DescriptorSetLayoutHashTableKey
- {
- VkShaderStageFlagBits shaderStage;
- // Category 1: read resources
- Uint32 samplerCount;
- Uint32 storageBufferCount;
- Uint32 storageTextureCount;
- // Category 2: write resources
- Uint32 writeStorageBufferCount;
- Uint32 writeStorageTextureCount;
- // Category 3: uniform buffers
- Uint32 uniformBufferCount;
- } DescriptorSetLayoutHashTableKey;
- typedef uint32_t DescriptorSetLayoutID;
- typedef struct DescriptorSetLayout
- {
- DescriptorSetLayoutID ID;
- VkDescriptorSetLayout descriptorSetLayout;
- // Category 1: read resources
- Uint32 samplerCount;
- Uint32 storageBufferCount;
- Uint32 storageTextureCount;
- // Category 2: write resources
- Uint32 writeStorageBufferCount;
- Uint32 writeStorageTextureCount;
- // Category 3: uniform buffers
- Uint32 uniformBufferCount;
- } DescriptorSetLayout;
- typedef struct GraphicsPipelineResourceLayoutHashTableKey
- {
- Uint32 vertexSamplerCount;
- Uint32 vertexStorageTextureCount;
- Uint32 vertexStorageBufferCount;
- Uint32 vertexUniformBufferCount;
- Uint32 fragmentSamplerCount;
- Uint32 fragmentStorageTextureCount;
- Uint32 fragmentStorageBufferCount;
- Uint32 fragmentUniformBufferCount;
- } GraphicsPipelineResourceLayoutHashTableKey;
- typedef struct VulkanGraphicsPipelineResourceLayout
- {
- VkPipelineLayout pipelineLayout;
- /*
- * Descriptor set layout is as follows:
- * 0: vertex resources
- * 1: vertex uniform buffers
- * 2: fragment resources
- * 3: fragment uniform buffers
- */
- DescriptorSetLayout *descriptorSetLayouts[4];
- Uint32 vertexSamplerCount;
- Uint32 vertexStorageTextureCount;
- Uint32 vertexStorageBufferCount;
- Uint32 vertexUniformBufferCount;
- Uint32 fragmentSamplerCount;
- Uint32 fragmentStorageTextureCount;
- Uint32 fragmentStorageBufferCount;
- Uint32 fragmentUniformBufferCount;
- } VulkanGraphicsPipelineResourceLayout;
- typedef struct VulkanGraphicsPipeline
- {
- GraphicsPipelineCommonHeader header;
- VkPipeline pipeline;
- SDL_GPUPrimitiveType primitiveType;
- VulkanGraphicsPipelineResourceLayout *resourceLayout;
- VulkanShader *vertexShader;
- VulkanShader *fragmentShader;
- SDL_AtomicInt referenceCount;
- } VulkanGraphicsPipeline;
- typedef struct ComputePipelineResourceLayoutHashTableKey
- {
- Uint32 samplerCount;
- Uint32 readonlyStorageTextureCount;
- Uint32 readonlyStorageBufferCount;
- Uint32 readWriteStorageTextureCount;
- Uint32 readWriteStorageBufferCount;
- Uint32 uniformBufferCount;
- } ComputePipelineResourceLayoutHashTableKey;
- typedef struct VulkanComputePipelineResourceLayout
- {
- VkPipelineLayout pipelineLayout;
- /*
- * Descriptor set layout is as follows:
- * 0: samplers, then read-only textures, then read-only buffers
- * 1: write-only textures, then write-only buffers
- * 2: uniform buffers
- */
- DescriptorSetLayout *descriptorSetLayouts[3];
- Uint32 numSamplers;
- Uint32 numReadonlyStorageTextures;
- Uint32 numReadonlyStorageBuffers;
- Uint32 numReadWriteStorageTextures;
- Uint32 numReadWriteStorageBuffers;
- Uint32 numUniformBuffers;
- } VulkanComputePipelineResourceLayout;
- typedef struct VulkanComputePipeline
- {
- ComputePipelineCommonHeader header;
- VkShaderModule shaderModule;
- VkPipeline pipeline;
- VulkanComputePipelineResourceLayout *resourceLayout;
- SDL_AtomicInt referenceCount;
- } VulkanComputePipeline;
- typedef struct RenderPassColorTargetDescription
- {
- VkFormat format;
- SDL_GPULoadOp loadOp;
- SDL_GPUStoreOp storeOp;
- } RenderPassColorTargetDescription;
- typedef struct RenderPassDepthStencilTargetDescription
- {
- VkFormat format;
- SDL_GPULoadOp loadOp;
- SDL_GPUStoreOp storeOp;
- SDL_GPULoadOp stencilLoadOp;
- SDL_GPUStoreOp stencilStoreOp;
- } RenderPassDepthStencilTargetDescription;
- typedef struct CommandPoolHashTableKey
- {
- SDL_ThreadID threadID;
- } CommandPoolHashTableKey;
- typedef struct RenderPassHashTableKey
- {
- RenderPassColorTargetDescription colorTargetDescriptions[MAX_COLOR_TARGET_BINDINGS];
- Uint32 numColorTargets;
- VkFormat resolveTargetFormats[MAX_COLOR_TARGET_BINDINGS];
- Uint32 numResolveTargets;
- RenderPassDepthStencilTargetDescription depthStencilTargetDescription;
- VkSampleCountFlagBits sampleCount;
- } RenderPassHashTableKey;
- typedef struct VulkanRenderPassHashTableValue
- {
- VkRenderPass handle;
- } VulkanRenderPassHashTableValue;
- typedef struct FramebufferHashTableKey
- {
- VkImageView colorAttachmentViews[MAX_COLOR_TARGET_BINDINGS];
- Uint32 numColorTargets;
- VkImageView resolveAttachmentViews[MAX_COLOR_TARGET_BINDINGS];
- Uint32 numResolveAttachments;
- VkImageView depthStencilAttachmentView;
- Uint32 width;
- Uint32 height;
- } FramebufferHashTableKey;
- // Command structures
- typedef struct VulkanFencePool
- {
- SDL_Mutex *lock;
- VulkanFenceHandle **availableFences;
- Uint32 availableFenceCount;
- Uint32 availableFenceCapacity;
- } VulkanFencePool;
- typedef struct VulkanCommandPool VulkanCommandPool;
- typedef struct VulkanRenderer VulkanRenderer;
- typedef struct VulkanCommandBuffer
- {
- CommandBufferCommonHeader common;
- VulkanRenderer *renderer;
- VkCommandBuffer commandBuffer;
- VulkanCommandPool *commandPool;
- VulkanPresentData *presentDatas;
- Uint32 presentDataCount;
- Uint32 presentDataCapacity;
- VkSemaphore *waitSemaphores;
- Uint32 waitSemaphoreCount;
- Uint32 waitSemaphoreCapacity;
- VkSemaphore *signalSemaphores;
- Uint32 signalSemaphoreCount;
- Uint32 signalSemaphoreCapacity;
- VulkanComputePipeline *currentComputePipeline;
- VulkanGraphicsPipeline *currentGraphicsPipeline;
- // Keep track of resources transitioned away from their default state to barrier them on pass end
- VulkanTextureSubresource *colorAttachmentSubresources[MAX_COLOR_TARGET_BINDINGS];
- Uint32 colorAttachmentSubresourceCount;
- VulkanTextureSubresource *resolveAttachmentSubresources[MAX_COLOR_TARGET_BINDINGS];
- Uint32 resolveAttachmentSubresourceCount;
- VulkanTextureSubresource *depthStencilAttachmentSubresource; // may be NULL
- // Dynamic state
- VkViewport currentViewport;
- VkRect2D currentScissor;
- float blendConstants[4];
- Uint8 stencilRef;
- // Resource bind state
- DescriptorSetCache *descriptorSetCache; // acquired when command buffer is acquired
- bool needNewVertexResourceDescriptorSet;
- bool needNewVertexUniformDescriptorSet;
- bool needNewVertexUniformOffsets;
- bool needNewFragmentResourceDescriptorSet;
- bool needNewFragmentUniformDescriptorSet;
- bool needNewFragmentUniformOffsets;
- bool needNewComputeReadOnlyDescriptorSet;
- bool needNewComputeReadWriteDescriptorSet;
- bool needNewComputeUniformDescriptorSet;
- bool needNewComputeUniformOffsets;
- VkDescriptorSet vertexResourceDescriptorSet;
- VkDescriptorSet vertexUniformDescriptorSet;
- VkDescriptorSet fragmentResourceDescriptorSet;
- VkDescriptorSet fragmentUniformDescriptorSet;
- VkDescriptorSet computeReadOnlyDescriptorSet;
- VkDescriptorSet computeReadWriteDescriptorSet;
- VkDescriptorSet computeUniformDescriptorSet;
- VkBuffer vertexBuffers[MAX_VERTEX_BUFFERS];
- VkDeviceSize vertexBufferOffsets[MAX_VERTEX_BUFFERS];
- Uint32 vertexBufferCount;
- bool needVertexBufferBind;
- VkImageView vertexSamplerTextureViewBindings[MAX_TEXTURE_SAMPLERS_PER_STAGE];
- VkSampler vertexSamplerBindings[MAX_TEXTURE_SAMPLERS_PER_STAGE];
- VkImageView vertexStorageTextureViewBindings[MAX_STORAGE_TEXTURES_PER_STAGE];
- VkBuffer vertexStorageBufferBindings[MAX_STORAGE_BUFFERS_PER_STAGE];
- VkImageView fragmentSamplerTextureViewBindings[MAX_TEXTURE_SAMPLERS_PER_STAGE];
- VkSampler fragmentSamplerBindings[MAX_TEXTURE_SAMPLERS_PER_STAGE];
- VkImageView fragmentStorageTextureViewBindings[MAX_STORAGE_TEXTURES_PER_STAGE];
- VkBuffer fragmentStorageBufferBindings[MAX_STORAGE_BUFFERS_PER_STAGE];
- VkImageView computeSamplerTextureViewBindings[MAX_TEXTURE_SAMPLERS_PER_STAGE];
- VkSampler computeSamplerBindings[MAX_TEXTURE_SAMPLERS_PER_STAGE];
- VkImageView readOnlyComputeStorageTextureViewBindings[MAX_STORAGE_TEXTURES_PER_STAGE];
- VkBuffer readOnlyComputeStorageBufferBindings[MAX_STORAGE_BUFFERS_PER_STAGE];
- // Track these separately because barriers can happen mid compute pass
- VulkanTexture *readOnlyComputeStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE];
- VulkanBuffer *readOnlyComputeStorageBuffers[MAX_STORAGE_BUFFERS_PER_STAGE];
- VkImageView readWriteComputeStorageTextureViewBindings[MAX_COMPUTE_WRITE_TEXTURES];
- VkBuffer readWriteComputeStorageBufferBindings[MAX_COMPUTE_WRITE_BUFFERS];
- // Track these separately because they are barriered when the compute pass begins
- VulkanTextureSubresource *readWriteComputeStorageTextureSubresources[MAX_COMPUTE_WRITE_TEXTURES];
- Uint32 readWriteComputeStorageTextureSubresourceCount;
- VulkanBuffer *readWriteComputeStorageBuffers[MAX_COMPUTE_WRITE_BUFFERS];
- // Uniform buffers
- VulkanUniformBuffer *vertexUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE];
- VulkanUniformBuffer *fragmentUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE];
- VulkanUniformBuffer *computeUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE];
- // Track used resources
- VulkanBuffer **usedBuffers;
- Sint32 usedBufferCount;
- Sint32 usedBufferCapacity;
- VulkanTexture **usedTextures;
- Sint32 usedTextureCount;
- Sint32 usedTextureCapacity;
- VulkanSampler **usedSamplers;
- Sint32 usedSamplerCount;
- Sint32 usedSamplerCapacity;
- VulkanGraphicsPipeline **usedGraphicsPipelines;
- Sint32 usedGraphicsPipelineCount;
- Sint32 usedGraphicsPipelineCapacity;
- VulkanComputePipeline **usedComputePipelines;
- Sint32 usedComputePipelineCount;
- Sint32 usedComputePipelineCapacity;
- VulkanFramebuffer **usedFramebuffers;
- Sint32 usedFramebufferCount;
- Sint32 usedFramebufferCapacity;
- VulkanUniformBuffer **usedUniformBuffers;
- Sint32 usedUniformBufferCount;
- Sint32 usedUniformBufferCapacity;
- VulkanFenceHandle *inFlightFence;
- bool autoReleaseFence;
- bool swapchainRequested;
- bool isDefrag; // Whether this CB was created for defragging
- } VulkanCommandBuffer;
- struct VulkanCommandPool
- {
- SDL_ThreadID threadID;
- VkCommandPool commandPool;
- VulkanCommandBuffer **inactiveCommandBuffers;
- Uint32 inactiveCommandBufferCapacity;
- Uint32 inactiveCommandBufferCount;
- };
- // Feature Checks
- typedef struct VulkanFeatures
- {
- Uint32 desiredApiVersion;
- VkPhysicalDeviceFeatures desiredVulkan10DeviceFeatures;
- VkPhysicalDeviceVulkan11Features desiredVulkan11DeviceFeatures;
- VkPhysicalDeviceVulkan12Features desiredVulkan12DeviceFeatures;
- VkPhysicalDeviceVulkan13Features desiredVulkan13DeviceFeatures;
- bool usesCustomVulkanOptions;
- Uint32 additionalDeviceExtensionCount;
- const char **additionalDeviceExtensionNames;
- Uint32 additionalInstanceExtensionCount;
- const char **additionalInstanceExtensionNames;
- } VulkanFeatures;
- // Context
- struct VulkanRenderer
- {
- VkInstance instance;
- VkPhysicalDevice physicalDevice;
- VkPhysicalDeviceProperties2KHR physicalDeviceProperties;
- VkPhysicalDeviceDriverPropertiesKHR physicalDeviceDriverProperties;
- VkDevice logicalDevice;
- Uint8 integratedMemoryNotification;
- Uint8 outOfDeviceLocalMemoryWarning;
- Uint8 outofBARMemoryWarning;
- Uint8 fillModeOnlyWarning;
- bool debugMode;
- bool preferLowPower;
- bool requireHardwareAcceleration;
- SDL_PropertiesID props;
- Uint32 allowedFramesInFlight;
- VulkanExtensions supports;
- bool supportsDebugUtils;
- bool supportsColorspace;
- bool supportsPhysicalDeviceProperties2;
- bool supportsFillModeNonSolid;
- bool supportsMultiDrawIndirect;
- VulkanMemoryAllocator *memoryAllocator;
- VkPhysicalDeviceMemoryProperties memoryProperties;
- bool checkEmptyAllocations;
- WindowData **claimedWindows;
- Uint32 claimedWindowCount;
- Uint32 claimedWindowCapacity;
- Uint32 queueFamilyIndex;
- VkQueue unifiedQueue;
- VulkanCommandBuffer **submittedCommandBuffers;
- Uint32 submittedCommandBufferCount;
- Uint32 submittedCommandBufferCapacity;
- VulkanFencePool fencePool;
- SDL_HashTable *commandPoolHashTable;
- SDL_HashTable *renderPassHashTable;
- SDL_HashTable *framebufferHashTable;
- SDL_HashTable *graphicsPipelineResourceLayoutHashTable;
- SDL_HashTable *computePipelineResourceLayoutHashTable;
- SDL_HashTable *descriptorSetLayoutHashTable;
- VulkanUniformBuffer **uniformBufferPool;
- Uint32 uniformBufferPoolCount;
- Uint32 uniformBufferPoolCapacity;
- DescriptorSetCache **descriptorSetCachePool;
- Uint32 descriptorSetCachePoolCount;
- Uint32 descriptorSetCachePoolCapacity;
- SDL_AtomicInt layoutResourceID;
- Uint32 minUBOAlignment;
- // Deferred resource destruction
- VulkanTexture **texturesToDestroy;
- Uint32 texturesToDestroyCount;
- Uint32 texturesToDestroyCapacity;
- VulkanBuffer **buffersToDestroy;
- Uint32 buffersToDestroyCount;
- Uint32 buffersToDestroyCapacity;
- VulkanSampler **samplersToDestroy;
- Uint32 samplersToDestroyCount;
- Uint32 samplersToDestroyCapacity;
- VulkanGraphicsPipeline **graphicsPipelinesToDestroy;
- Uint32 graphicsPipelinesToDestroyCount;
- Uint32 graphicsPipelinesToDestroyCapacity;
- VulkanComputePipeline **computePipelinesToDestroy;
- Uint32 computePipelinesToDestroyCount;
- Uint32 computePipelinesToDestroyCapacity;
- VulkanShader **shadersToDestroy;
- Uint32 shadersToDestroyCount;
- Uint32 shadersToDestroyCapacity;
- VulkanFramebuffer **framebuffersToDestroy;
- Uint32 framebuffersToDestroyCount;
- Uint32 framebuffersToDestroyCapacity;
- SDL_Mutex *allocatorLock;
- SDL_Mutex *disposeLock;
- SDL_Mutex *submitLock;
- SDL_Mutex *acquireCommandBufferLock;
- SDL_Mutex *acquireUniformBufferLock;
- SDL_Mutex *renderPassFetchLock;
- SDL_Mutex *framebufferFetchLock;
- SDL_Mutex *graphicsPipelineLayoutFetchLock;
- SDL_Mutex *computePipelineLayoutFetchLock;
- SDL_Mutex *descriptorSetLayoutFetchLock;
- SDL_Mutex *windowLock;
- Uint8 defragInProgress;
- VulkanMemoryAllocation **allocationsToDefrag;
- Uint32 allocationsToDefragCount;
- Uint32 allocationsToDefragCapacity;
- #define VULKAN_INSTANCE_FUNCTION(func) \
- PFN_##func func;
- #define VULKAN_DEVICE_FUNCTION(func) \
- PFN_##func func;
- #include "SDL_gpu_vulkan_vkfuncs.h"
- };
- // Forward declarations
- static bool VULKAN_INTERNAL_DefragmentMemory(VulkanRenderer *renderer, VulkanCommandBuffer *commandBuffer);
- static bool VULKAN_INTERNAL_BeginCommandBuffer(VulkanRenderer *renderer, VulkanCommandBuffer *commandBuffer);
- static void VULKAN_ReleaseWindow(SDL_GPURenderer *driverData, SDL_Window *window);
- static bool VULKAN_Wait(SDL_GPURenderer *driverData);
- static bool VULKAN_WaitForFences(SDL_GPURenderer *driverData, bool waitAll, SDL_GPUFence *const *fences, Uint32 numFences);
- static bool VULKAN_Submit(SDL_GPUCommandBuffer *commandBuffer);
- static SDL_GPUCommandBuffer *VULKAN_AcquireCommandBuffer(SDL_GPURenderer *driverData);
- // Error Handling
- static inline const char *VkErrorMessages(VkResult code)
- {
- #define ERR_TO_STR(e) \
- case e: \
- return #e;
- switch (code) {
- ERR_TO_STR(VK_ERROR_OUT_OF_HOST_MEMORY)
- ERR_TO_STR(VK_ERROR_OUT_OF_DEVICE_MEMORY)
- ERR_TO_STR(VK_ERROR_FRAGMENTED_POOL)
- ERR_TO_STR(VK_ERROR_OUT_OF_POOL_MEMORY)
- ERR_TO_STR(VK_ERROR_INITIALIZATION_FAILED)
- ERR_TO_STR(VK_ERROR_LAYER_NOT_PRESENT)
- ERR_TO_STR(VK_ERROR_EXTENSION_NOT_PRESENT)
- ERR_TO_STR(VK_ERROR_FEATURE_NOT_PRESENT)
- ERR_TO_STR(VK_ERROR_TOO_MANY_OBJECTS)
- ERR_TO_STR(VK_ERROR_DEVICE_LOST)
- ERR_TO_STR(VK_ERROR_INCOMPATIBLE_DRIVER)
- ERR_TO_STR(VK_ERROR_OUT_OF_DATE_KHR)
- ERR_TO_STR(VK_ERROR_SURFACE_LOST_KHR)
- ERR_TO_STR(VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT)
- ERR_TO_STR(VK_SUBOPTIMAL_KHR)
- ERR_TO_STR(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR)
- ERR_TO_STR(VK_ERROR_INVALID_SHADER_NV)
- default:
- return "Unhandled VkResult!";
- }
- #undef ERR_TO_STR
- }
- #define SET_ERROR(fmt, msg) \
- do { \
- if (renderer->debugMode) { \
- SDL_LogError(SDL_LOG_CATEGORY_GPU, fmt, msg); \
- } \
- SDL_SetError((fmt), (msg)); \
- } while (0)
- #define SET_STRING_ERROR(msg) SET_ERROR("%s", msg)
- #define SET_ERROR_AND_RETURN(fmt, msg, ret) \
- do { \
- SET_ERROR(fmt, msg); \
- return ret; \
- } while (0)
- #define SET_STRING_ERROR_AND_RETURN(msg, ret) SET_ERROR_AND_RETURN("%s", msg, ret)
- #define CHECK_VULKAN_ERROR_AND_RETURN(res, fn, ret) \
- do { \
- if ((res) != VK_SUCCESS) { \
- if (renderer->debugMode) { \
- SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s %s", #fn, VkErrorMessages(res)); \
- } \
- SDL_SetError("%s %s", #fn, VkErrorMessages(res)); \
- return (ret); \
- } \
- } while (0)
- // Utility
- static inline VkPolygonMode SDLToVK_PolygonMode(
- VulkanRenderer *renderer,
- SDL_GPUFillMode mode)
- {
- if (mode == SDL_GPU_FILLMODE_FILL) {
- return VK_POLYGON_MODE_FILL; // always available!
- }
- if (renderer->supportsFillModeNonSolid && mode == SDL_GPU_FILLMODE_LINE) {
- return VK_POLYGON_MODE_LINE;
- }
- if (!renderer->fillModeOnlyWarning) {
- SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Unsupported fill mode requested, using FILL!");
- renderer->fillModeOnlyWarning = 1;
- }
- return VK_POLYGON_MODE_FILL;
- }
- // Memory Management
- // Vulkan: Memory Allocation
- static inline VkDeviceSize VULKAN_INTERNAL_NextHighestAlignment(
- VkDeviceSize n,
- VkDeviceSize align)
- {
- return align * ((n + align - 1) / align);
- }
- static inline Uint32 VULKAN_INTERNAL_NextHighestAlignment32(
- Uint32 n,
- Uint32 align)
- {
- return align * ((n + align - 1) / align);
- }
- static void VULKAN_INTERNAL_MakeMemoryUnavailable(
- VulkanMemoryAllocation *allocation)
- {
- Uint32 i, j;
- VulkanMemoryFreeRegion *freeRegion;
- allocation->availableForAllocation = 0;
- for (i = 0; i < allocation->freeRegionCount; i += 1) {
- freeRegion = allocation->freeRegions[i];
- // close the gap in the sorted list
- if (allocation->allocator->sortedFreeRegionCount > 1) {
- for (j = freeRegion->sortedIndex; j < allocation->allocator->sortedFreeRegionCount - 1; j += 1) {
- allocation->allocator->sortedFreeRegions[j] =
- allocation->allocator->sortedFreeRegions[j + 1];
- allocation->allocator->sortedFreeRegions[j]->sortedIndex = j;
- }
- }
- allocation->allocator->sortedFreeRegionCount -= 1;
- }
- }
- static void VULKAN_INTERNAL_MarkAllocationsForDefrag(
- VulkanRenderer *renderer)
- {
- Uint32 memoryType, allocationIndex;
- VulkanMemorySubAllocator *currentAllocator;
- for (memoryType = 0; memoryType < VK_MAX_MEMORY_TYPES; memoryType += 1) {
- currentAllocator = &renderer->memoryAllocator->subAllocators[memoryType];
- for (allocationIndex = 0; allocationIndex < currentAllocator->allocationCount; allocationIndex += 1) {
- if (currentAllocator->allocations[allocationIndex]->availableForAllocation == 1) {
- if (currentAllocator->allocations[allocationIndex]->freeRegionCount > 1) {
- EXPAND_ARRAY_IF_NEEDED(
- renderer->allocationsToDefrag,
- VulkanMemoryAllocation *,
- renderer->allocationsToDefragCount + 1,
- renderer->allocationsToDefragCapacity,
- renderer->allocationsToDefragCapacity * 2);
- renderer->allocationsToDefrag[renderer->allocationsToDefragCount] =
- currentAllocator->allocations[allocationIndex];
- renderer->allocationsToDefragCount += 1;
- VULKAN_INTERNAL_MakeMemoryUnavailable(
- currentAllocator->allocations[allocationIndex]);
- }
- }
- }
- }
- }
- static void VULKAN_INTERNAL_RemoveMemoryFreeRegion(
- VulkanRenderer *renderer,
- VulkanMemoryFreeRegion *freeRegion)
- {
- Uint32 i;
- SDL_LockMutex(renderer->allocatorLock);
- if (freeRegion->allocation->availableForAllocation) {
- // close the gap in the sorted list
- if (freeRegion->allocation->allocator->sortedFreeRegionCount > 1) {
- for (i = freeRegion->sortedIndex; i < freeRegion->allocation->allocator->sortedFreeRegionCount - 1; i += 1) {
- freeRegion->allocation->allocator->sortedFreeRegions[i] =
- freeRegion->allocation->allocator->sortedFreeRegions[i + 1];
- freeRegion->allocation->allocator->sortedFreeRegions[i]->sortedIndex = i;
- }
- }
- freeRegion->allocation->allocator->sortedFreeRegionCount -= 1;
- }
- // close the gap in the buffer list
- if (freeRegion->allocation->freeRegionCount > 1 && freeRegion->allocationIndex != freeRegion->allocation->freeRegionCount - 1) {
- freeRegion->allocation->freeRegions[freeRegion->allocationIndex] =
- freeRegion->allocation->freeRegions[freeRegion->allocation->freeRegionCount - 1];
- freeRegion->allocation->freeRegions[freeRegion->allocationIndex]->allocationIndex =
- freeRegion->allocationIndex;
- }
- freeRegion->allocation->freeRegionCount -= 1;
- freeRegion->allocation->freeSpace -= freeRegion->size;
- SDL_free(freeRegion);
- SDL_UnlockMutex(renderer->allocatorLock);
- }
- static void VULKAN_INTERNAL_NewMemoryFreeRegion(
- VulkanRenderer *renderer,
- VulkanMemoryAllocation *allocation,
- VkDeviceSize offset,
- VkDeviceSize size)
- {
- VulkanMemoryFreeRegion *newFreeRegion;
- VkDeviceSize newOffset, newSize;
- Sint32 insertionIndex = 0;
- SDL_LockMutex(renderer->allocatorLock);
- // look for an adjacent region to merge
- for (Sint32 i = allocation->freeRegionCount - 1; i >= 0; i -= 1) {
- // check left side
- if (allocation->freeRegions[i]->offset + allocation->freeRegions[i]->size == offset) {
- newOffset = allocation->freeRegions[i]->offset;
- newSize = allocation->freeRegions[i]->size + size;
- VULKAN_INTERNAL_RemoveMemoryFreeRegion(renderer, allocation->freeRegions[i]);
- VULKAN_INTERNAL_NewMemoryFreeRegion(renderer, allocation, newOffset, newSize);
- SDL_UnlockMutex(renderer->allocatorLock);
- return;
- }
- // check right side
- if (allocation->freeRegions[i]->offset == offset + size) {
- newOffset = offset;
- newSize = allocation->freeRegions[i]->size + size;
- VULKAN_INTERNAL_RemoveMemoryFreeRegion(renderer, allocation->freeRegions[i]);
- VULKAN_INTERNAL_NewMemoryFreeRegion(renderer, allocation, newOffset, newSize);
- SDL_UnlockMutex(renderer->allocatorLock);
- return;
- }
- }
- // region is not contiguous with another free region, make a new one
- allocation->freeRegionCount += 1;
- if (allocation->freeRegionCount > allocation->freeRegionCapacity) {
- allocation->freeRegionCapacity *= 2;
- allocation->freeRegions = SDL_realloc(
- allocation->freeRegions,
- sizeof(VulkanMemoryFreeRegion *) * allocation->freeRegionCapacity);
- }
- newFreeRegion = SDL_malloc(sizeof(VulkanMemoryFreeRegion));
- newFreeRegion->offset = offset;
- newFreeRegion->size = size;
- newFreeRegion->allocation = allocation;
- allocation->freeSpace += size;
- allocation->freeRegions[allocation->freeRegionCount - 1] = newFreeRegion;
- newFreeRegion->allocationIndex = allocation->freeRegionCount - 1;
- if (allocation->availableForAllocation) {
- for (Uint32 i = 0; i < allocation->allocator->sortedFreeRegionCount; i += 1) {
- if (allocation->allocator->sortedFreeRegions[i]->size < size) {
- // this is where the new region should go
- break;
- }
- insertionIndex += 1;
- }
- if (allocation->allocator->sortedFreeRegionCount + 1 > allocation->allocator->sortedFreeRegionCapacity) {
- allocation->allocator->sortedFreeRegionCapacity *= 2;
- allocation->allocator->sortedFreeRegions = SDL_realloc(
- allocation->allocator->sortedFreeRegions,
- sizeof(VulkanMemoryFreeRegion *) * allocation->allocator->sortedFreeRegionCapacity);
- }
- // perform insertion sort
- if (allocation->allocator->sortedFreeRegionCount > 0 && (Uint32)insertionIndex != allocation->allocator->sortedFreeRegionCount) {
- for (Sint32 i = allocation->allocator->sortedFreeRegionCount; i > insertionIndex && i > 0; i -= 1) {
- allocation->allocator->sortedFreeRegions[i] = allocation->allocator->sortedFreeRegions[i - 1];
- allocation->allocator->sortedFreeRegions[i]->sortedIndex = i;
- }
- }
- allocation->allocator->sortedFreeRegionCount += 1;
- allocation->allocator->sortedFreeRegions[insertionIndex] = newFreeRegion;
- newFreeRegion->sortedIndex = insertionIndex;
- }
- SDL_UnlockMutex(renderer->allocatorLock);
- }
- static VulkanMemoryUsedRegion *VULKAN_INTERNAL_NewMemoryUsedRegion(
- VulkanRenderer *renderer,
- VulkanMemoryAllocation *allocation,
- VkDeviceSize offset,
- VkDeviceSize size,
- VkDeviceSize resourceOffset,
- VkDeviceSize resourceSize,
- VkDeviceSize alignment)
- {
- VulkanMemoryUsedRegion *memoryUsedRegion;
- SDL_LockMutex(renderer->allocatorLock);
- if (allocation->usedRegionCount == allocation->usedRegionCapacity) {
- allocation->usedRegionCapacity *= 2;
- allocation->usedRegions = SDL_realloc(
- allocation->usedRegions,
- allocation->usedRegionCapacity * sizeof(VulkanMemoryUsedRegion *));
- }
- memoryUsedRegion = SDL_malloc(sizeof(VulkanMemoryUsedRegion));
- memoryUsedRegion->allocation = allocation;
- memoryUsedRegion->offset = offset;
- memoryUsedRegion->size = size;
- memoryUsedRegion->resourceOffset = resourceOffset;
- memoryUsedRegion->resourceSize = resourceSize;
- memoryUsedRegion->alignment = alignment;
- allocation->usedSpace += size;
- allocation->usedRegions[allocation->usedRegionCount] = memoryUsedRegion;
- allocation->usedRegionCount += 1;
- SDL_UnlockMutex(renderer->allocatorLock);
- return memoryUsedRegion;
- }
- static void VULKAN_INTERNAL_RemoveMemoryUsedRegion(
- VulkanRenderer *renderer,
- VulkanMemoryUsedRegion *usedRegion)
- {
- Uint32 i;
- SDL_LockMutex(renderer->allocatorLock);
- for (i = 0; i < usedRegion->allocation->usedRegionCount; i += 1) {
- if (usedRegion->allocation->usedRegions[i] == usedRegion) {
- // plug the hole
- if (i != usedRegion->allocation->usedRegionCount - 1) {
- usedRegion->allocation->usedRegions[i] = usedRegion->allocation->usedRegions[usedRegion->allocation->usedRegionCount - 1];
- }
- break;
- }
- }
- usedRegion->allocation->usedSpace -= usedRegion->size;
- usedRegion->allocation->usedRegionCount -= 1;
- VULKAN_INTERNAL_NewMemoryFreeRegion(
- renderer,
- usedRegion->allocation,
- usedRegion->offset,
- usedRegion->size);
- if (usedRegion->allocation->usedRegionCount == 0) {
- renderer->checkEmptyAllocations = true;
- }
- SDL_free(usedRegion);
- SDL_UnlockMutex(renderer->allocatorLock);
- }
- static bool VULKAN_INTERNAL_CheckMemoryTypeArrayUnique(
- Uint32 memoryTypeIndex,
- const Uint32 *memoryTypeIndexArray,
- Uint32 count)
- {
- Uint32 i = 0;
- for (i = 0; i < count; i += 1) {
- if (memoryTypeIndexArray[i] == memoryTypeIndex) {
- return false;
- }
- }
- return true;
- }
- /* Returns an array of memory type indices in order of preference.
- * Memory types are requested with the following three guidelines:
- *
- * Required: Absolutely necessary
- * Preferred: Nice to have, but not necessary
- * Tolerable: Can be allowed if there are no other options
- *
- * We return memory types in this order:
- * 1. Required and preferred. This is the best category.
- * 2. Required only.
- * 3. Required, preferred, and tolerable.
- * 4. Required and tolerable. This is the worst category.
- */
- static Uint32 *VULKAN_INTERNAL_FindBestMemoryTypes(
- VulkanRenderer *renderer,
- Uint32 typeFilter,
- VkMemoryPropertyFlags requiredProperties,
- VkMemoryPropertyFlags preferredProperties,
- VkMemoryPropertyFlags tolerableProperties,
- Uint32 *pCount)
- {
- Uint32 i;
- Uint32 index = 0;
- Uint32 *result = SDL_malloc(sizeof(Uint32) * renderer->memoryProperties.memoryTypeCount);
- // required + preferred + !tolerable
- for (i = 0; i < renderer->memoryProperties.memoryTypeCount; i += 1) {
- if ((typeFilter & (1 << i)) &&
- (renderer->memoryProperties.memoryTypes[i].propertyFlags & requiredProperties) == requiredProperties &&
- (renderer->memoryProperties.memoryTypes[i].propertyFlags & preferredProperties) == preferredProperties &&
- (renderer->memoryProperties.memoryTypes[i].propertyFlags & tolerableProperties) == 0) {
- if (VULKAN_INTERNAL_CheckMemoryTypeArrayUnique(
- i,
- result,
- index)) {
- result[index] = i;
- index += 1;
- }
- }
- }
- // required + !preferred + !tolerable
- for (i = 0; i < renderer->memoryProperties.memoryTypeCount; i += 1) {
- if ((typeFilter & (1 << i)) &&
- (renderer->memoryProperties.memoryTypes[i].propertyFlags & requiredProperties) == requiredProperties &&
- (renderer->memoryProperties.memoryTypes[i].propertyFlags & preferredProperties) == 0 &&
- (renderer->memoryProperties.memoryTypes[i].propertyFlags & tolerableProperties) == 0) {
- if (VULKAN_INTERNAL_CheckMemoryTypeArrayUnique(
- i,
- result,
- index)) {
- result[index] = i;
- index += 1;
- }
- }
- }
- // required + preferred + tolerable
- for (i = 0; i < renderer->memoryProperties.memoryTypeCount; i += 1) {
- if ((typeFilter & (1 << i)) &&
- (renderer->memoryProperties.memoryTypes[i].propertyFlags & requiredProperties) == requiredProperties &&
- (renderer->memoryProperties.memoryTypes[i].propertyFlags & preferredProperties) == preferredProperties &&
- (renderer->memoryProperties.memoryTypes[i].propertyFlags & tolerableProperties) == tolerableProperties) {
- if (VULKAN_INTERNAL_CheckMemoryTypeArrayUnique(
- i,
- result,
- index)) {
- result[index] = i;
- index += 1;
- }
- }
- }
- // required + !preferred + tolerable
- for (i = 0; i < renderer->memoryProperties.memoryTypeCount; i += 1) {
- if ((typeFilter & (1 << i)) &&
- (renderer->memoryProperties.memoryTypes[i].propertyFlags & requiredProperties) == requiredProperties &&
- (renderer->memoryProperties.memoryTypes[i].propertyFlags & preferredProperties) == 0 &&
- (renderer->memoryProperties.memoryTypes[i].propertyFlags & tolerableProperties) == tolerableProperties) {
- if (VULKAN_INTERNAL_CheckMemoryTypeArrayUnique(
- i,
- result,
- index)) {
- result[index] = i;
- index += 1;
- }
- }
- }
- *pCount = index;
- return result;
- }
- static Uint32 *VULKAN_INTERNAL_FindBestBufferMemoryTypes(
- VulkanRenderer *renderer,
- VkBuffer buffer,
- VkMemoryPropertyFlags requiredMemoryProperties,
- VkMemoryPropertyFlags preferredMemoryProperties,
- VkMemoryPropertyFlags tolerableMemoryProperties,
- VkMemoryRequirements *pMemoryRequirements,
- Uint32 *pCount)
- {
- renderer->vkGetBufferMemoryRequirements(
- renderer->logicalDevice,
- buffer,
- pMemoryRequirements);
- return VULKAN_INTERNAL_FindBestMemoryTypes(
- renderer,
- pMemoryRequirements->memoryTypeBits,
- requiredMemoryProperties,
- preferredMemoryProperties,
- tolerableMemoryProperties,
- pCount);
- }
- static Uint32 *VULKAN_INTERNAL_FindBestImageMemoryTypes(
- VulkanRenderer *renderer,
- VkImage image,
- VkMemoryPropertyFlags preferredMemoryPropertyFlags,
- VkMemoryRequirements *pMemoryRequirements,
- Uint32 *pCount)
- {
- renderer->vkGetImageMemoryRequirements(
- renderer->logicalDevice,
- image,
- pMemoryRequirements);
- return VULKAN_INTERNAL_FindBestMemoryTypes(
- renderer,
- pMemoryRequirements->memoryTypeBits,
- 0,
- preferredMemoryPropertyFlags,
- 0,
- pCount);
- }
- static void VULKAN_INTERNAL_DeallocateMemory(
- VulkanRenderer *renderer,
- VulkanMemorySubAllocator *allocator,
- Uint32 allocationIndex)
- {
- Uint32 i;
- VulkanMemoryAllocation *allocation = allocator->allocations[allocationIndex];
- SDL_LockMutex(renderer->allocatorLock);
- // If this allocation was marked for defrag, cancel that
- for (i = 0; i < renderer->allocationsToDefragCount; i += 1) {
- if (allocation == renderer->allocationsToDefrag[i]) {
- renderer->allocationsToDefrag[i] = renderer->allocationsToDefrag[renderer->allocationsToDefragCount - 1];
- renderer->allocationsToDefragCount -= 1;
- break;
- }
- }
- for (i = 0; i < allocation->freeRegionCount; i += 1) {
- VULKAN_INTERNAL_RemoveMemoryFreeRegion(
- renderer,
- allocation->freeRegions[i]);
- }
- SDL_free(allocation->freeRegions);
- /* no need to iterate used regions because deallocate
- * only happens when there are 0 used regions
- */
- SDL_free(allocation->usedRegions);
- renderer->vkFreeMemory(
- renderer->logicalDevice,
- allocation->memory,
- NULL);
- SDL_DestroyMutex(allocation->memoryLock);
- SDL_free(allocation);
- if (allocationIndex != allocator->allocationCount - 1) {
- allocator->allocations[allocationIndex] = allocator->allocations[allocator->allocationCount - 1];
- }
- allocator->allocationCount -= 1;
- SDL_UnlockMutex(renderer->allocatorLock);
- }
- static Uint8 VULKAN_INTERNAL_AllocateMemory(
- VulkanRenderer *renderer,
- Uint32 memoryTypeIndex,
- VkDeviceSize allocationSize,
- Uint8 isHostVisible,
- VulkanMemoryAllocation **pMemoryAllocation)
- {
- VulkanMemoryAllocation *allocation;
- VulkanMemorySubAllocator *allocator = &renderer->memoryAllocator->subAllocators[memoryTypeIndex];
- VkMemoryAllocateInfo allocInfo;
- VkResult result;
- allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
- allocInfo.pNext = NULL;
- allocInfo.memoryTypeIndex = memoryTypeIndex;
- allocInfo.allocationSize = allocationSize;
- allocation = SDL_malloc(sizeof(VulkanMemoryAllocation));
- allocation->size = allocationSize;
- allocation->freeSpace = 0; // added by FreeRegions
- allocation->usedSpace = 0; // added by UsedRegions
- allocation->memoryLock = SDL_CreateMutex();
- allocator->allocationCount += 1;
- allocator->allocations = SDL_realloc(
- allocator->allocations,
- sizeof(VulkanMemoryAllocation *) * allocator->allocationCount);
- allocator->allocations[allocator->allocationCount - 1] = allocation;
- allocInfo.pNext = NULL;
- allocation->availableForAllocation = 1;
- allocation->usedRegions = SDL_malloc(sizeof(VulkanMemoryUsedRegion *));
- allocation->usedRegionCount = 0;
- allocation->usedRegionCapacity = 1;
- allocation->freeRegions = SDL_malloc(sizeof(VulkanMemoryFreeRegion *));
- allocation->freeRegionCount = 0;
- allocation->freeRegionCapacity = 1;
- allocation->allocator = allocator;
- result = renderer->vkAllocateMemory(
- renderer->logicalDevice,
- &allocInfo,
- NULL,
- &allocation->memory);
- if (result != VK_SUCCESS) {
- // Uh oh, we couldn't allocate, time to clean up
- SDL_free(allocation->freeRegions);
- allocator->allocationCount -= 1;
- allocator->allocations = SDL_realloc(
- allocator->allocations,
- sizeof(VulkanMemoryAllocation *) * allocator->allocationCount);
- SDL_free(allocation);
- return 0;
- }
- // Persistent mapping for host-visible memory
- if (isHostVisible) {
- result = renderer->vkMapMemory(
- renderer->logicalDevice,
- allocation->memory,
- 0,
- VK_WHOLE_SIZE,
- 0,
- (void **)&allocation->mapPointer);
- CHECK_VULKAN_ERROR_AND_RETURN(result, vkMapMemory, 0);
- } else {
- allocation->mapPointer = NULL;
- }
- VULKAN_INTERNAL_NewMemoryFreeRegion(
- renderer,
- allocation,
- 0,
- allocation->size);
- *pMemoryAllocation = allocation;
- return 1;
- }
- static Uint8 VULKAN_INTERNAL_BindBufferMemory(
- VulkanRenderer *renderer,
- VulkanMemoryUsedRegion *usedRegion,
- VkDeviceSize alignedOffset,
- VkBuffer buffer)
- {
- VkResult vulkanResult;
- SDL_LockMutex(usedRegion->allocation->memoryLock);
- vulkanResult = renderer->vkBindBufferMemory(
- renderer->logicalDevice,
- buffer,
- usedRegion->allocation->memory,
- alignedOffset);
- SDL_UnlockMutex(usedRegion->allocation->memoryLock);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkBindBufferMemory, 0);
- return 1;
- }
- static Uint8 VULKAN_INTERNAL_BindImageMemory(
- VulkanRenderer *renderer,
- VulkanMemoryUsedRegion *usedRegion,
- VkDeviceSize alignedOffset,
- VkImage image)
- {
- VkResult vulkanResult;
- SDL_LockMutex(usedRegion->allocation->memoryLock);
- vulkanResult = renderer->vkBindImageMemory(
- renderer->logicalDevice,
- image,
- usedRegion->allocation->memory,
- alignedOffset);
- SDL_UnlockMutex(usedRegion->allocation->memoryLock);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkBindImageMemory, 0);
- return 1;
- }
- static Uint8 VULKAN_INTERNAL_BindResourceMemory(
- VulkanRenderer *renderer,
- Uint32 memoryTypeIndex,
- VkMemoryRequirements *memoryRequirements,
- VkDeviceSize resourceSize, // may be different from requirements size!
- bool dedicated, // the entire memory allocation should be used for this resource
- VkBuffer buffer, // may be VK_NULL_HANDLE
- VkImage image, // may be VK_NULL_HANDLE
- VulkanMemoryUsedRegion **pMemoryUsedRegion)
- {
- VulkanMemoryAllocation *allocation;
- VulkanMemorySubAllocator *allocator;
- VulkanMemoryFreeRegion *region;
- VulkanMemoryFreeRegion *selectedRegion;
- VulkanMemoryUsedRegion *usedRegion;
- VkDeviceSize requiredSize, allocationSize;
- VkDeviceSize alignedOffset = 0;
- VkDeviceSize newRegionSize, newRegionOffset;
- Uint8 isHostVisible, smallAllocation, allocationResult;
- Sint32 i;
- isHostVisible =
- (renderer->memoryProperties.memoryTypes[memoryTypeIndex].propertyFlags &
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0;
- allocator = &renderer->memoryAllocator->subAllocators[memoryTypeIndex];
- requiredSize = memoryRequirements->size;
- smallAllocation = requiredSize <= SMALL_ALLOCATION_THRESHOLD;
- if ((buffer == VK_NULL_HANDLE && image == VK_NULL_HANDLE) ||
- (buffer != VK_NULL_HANDLE && image != VK_NULL_HANDLE)) {
- SDL_LogError(SDL_LOG_CATEGORY_GPU, "BindResourceMemory must be given either a VulkanBuffer or a VulkanTexture");
- return 0;
- }
- SDL_LockMutex(renderer->allocatorLock);
- selectedRegion = NULL;
- if (dedicated) {
- // Force an allocation
- allocationSize = requiredSize;
- } else {
- // Search for a suitable existing free region
- for (i = allocator->sortedFreeRegionCount - 1; i >= 0; i -= 1) {
- region = allocator->sortedFreeRegions[i];
- if (smallAllocation && region->allocation->size != SMALL_ALLOCATION_SIZE) {
- // region is not in a small allocation
- continue;
- }
- if (!smallAllocation && region->allocation->size == SMALL_ALLOCATION_SIZE) {
- // allocation is not small and current region is in a small allocation
- continue;
- }
- alignedOffset = VULKAN_INTERNAL_NextHighestAlignment(
- region->offset,
- memoryRequirements->alignment);
- if (alignedOffset + requiredSize <= region->offset + region->size) {
- selectedRegion = region;
- break;
- }
- }
- if (selectedRegion != NULL) {
- region = selectedRegion;
- allocation = region->allocation;
- usedRegion = VULKAN_INTERNAL_NewMemoryUsedRegion(
- renderer,
- allocation,
- region->offset,
- requiredSize + (alignedOffset - region->offset),
- alignedOffset,
- resourceSize,
- memoryRequirements->alignment);
- usedRegion->isBuffer = buffer != VK_NULL_HANDLE;
- newRegionSize = region->size - ((alignedOffset - region->offset) + requiredSize);
- newRegionOffset = alignedOffset + requiredSize;
- // remove and add modified region to re-sort
- VULKAN_INTERNAL_RemoveMemoryFreeRegion(renderer, region);
- // if size is 0, no need to re-insert
- if (newRegionSize != 0) {
- VULKAN_INTERNAL_NewMemoryFreeRegion(
- renderer,
- allocation,
- newRegionOffset,
- newRegionSize);
- }
- SDL_UnlockMutex(renderer->allocatorLock);
- if (buffer != VK_NULL_HANDLE) {
- if (!VULKAN_INTERNAL_BindBufferMemory(
- renderer,
- usedRegion,
- alignedOffset,
- buffer)) {
- VULKAN_INTERNAL_RemoveMemoryUsedRegion(
- renderer,
- usedRegion);
- return 0;
- }
- } else if (image != VK_NULL_HANDLE) {
- if (!VULKAN_INTERNAL_BindImageMemory(
- renderer,
- usedRegion,
- alignedOffset,
- image)) {
- VULKAN_INTERNAL_RemoveMemoryUsedRegion(
- renderer,
- usedRegion);
- return 0;
- }
- }
- *pMemoryUsedRegion = usedRegion;
- return 1;
- }
- // No suitable free regions exist, allocate a new memory region
- if (
- renderer->allocationsToDefragCount == 0 &&
- !renderer->defragInProgress) {
- // Mark currently fragmented allocations for defrag
- VULKAN_INTERNAL_MarkAllocationsForDefrag(renderer);
- }
- if (requiredSize > SMALL_ALLOCATION_THRESHOLD) {
- // allocate a page of required size aligned to LARGE_ALLOCATION_INCREMENT increments
- allocationSize =
- VULKAN_INTERNAL_NextHighestAlignment(requiredSize, LARGE_ALLOCATION_INCREMENT);
- } else {
- allocationSize = SMALL_ALLOCATION_SIZE;
- }
- }
- allocationResult = VULKAN_INTERNAL_AllocateMemory(
- renderer,
- memoryTypeIndex,
- allocationSize,
- isHostVisible,
- &allocation);
- // Uh oh, we're out of memory
- if (allocationResult == 0) {
- SDL_UnlockMutex(renderer->allocatorLock);
- // Responsibility of the caller to handle being out of memory
- return 2;
- }
- usedRegion = VULKAN_INTERNAL_NewMemoryUsedRegion(
- renderer,
- allocation,
- 0,
- requiredSize,
- 0,
- resourceSize,
- memoryRequirements->alignment);
- usedRegion->isBuffer = buffer != VK_NULL_HANDLE;
- region = allocation->freeRegions[0];
- newRegionOffset = region->offset + requiredSize;
- newRegionSize = region->size - requiredSize;
- VULKAN_INTERNAL_RemoveMemoryFreeRegion(renderer, region);
- if (newRegionSize != 0) {
- VULKAN_INTERNAL_NewMemoryFreeRegion(
- renderer,
- allocation,
- newRegionOffset,
- newRegionSize);
- }
- SDL_UnlockMutex(renderer->allocatorLock);
- if (buffer != VK_NULL_HANDLE) {
- if (!VULKAN_INTERNAL_BindBufferMemory(
- renderer,
- usedRegion,
- 0,
- buffer)) {
- VULKAN_INTERNAL_RemoveMemoryUsedRegion(
- renderer,
- usedRegion);
- return 0;
- }
- } else if (image != VK_NULL_HANDLE) {
- if (!VULKAN_INTERNAL_BindImageMemory(
- renderer,
- usedRegion,
- 0,
- image)) {
- VULKAN_INTERNAL_RemoveMemoryUsedRegion(
- renderer,
- usedRegion);
- return 0;
- }
- }
- *pMemoryUsedRegion = usedRegion;
- return 1;
- }
- static Uint8 VULKAN_INTERNAL_BindMemoryForImage(
- VulkanRenderer *renderer,
- VkImage image,
- VulkanMemoryUsedRegion **usedRegion)
- {
- Uint8 bindResult = 0;
- Uint32 memoryTypeCount = 0;
- Uint32 *memoryTypesToTry = NULL;
- Uint32 selectedMemoryTypeIndex = 0;
- Uint32 i;
- VkMemoryPropertyFlags preferredMemoryPropertyFlags;
- VkMemoryRequirements memoryRequirements;
- /* Vulkan memory types have several memory properties.
- *
- * Unlike buffers, images are always optimally stored device-local,
- * so that is the only property we prefer here.
- *
- * If memory is constrained, it is fine for the texture to not
- * be device-local.
- */
- preferredMemoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
- memoryTypesToTry = VULKAN_INTERNAL_FindBestImageMemoryTypes(
- renderer,
- image,
- preferredMemoryPropertyFlags,
- &memoryRequirements,
- &memoryTypeCount);
- for (i = 0; i < memoryTypeCount; i += 1) {
- bindResult = VULKAN_INTERNAL_BindResourceMemory(
- renderer,
- memoryTypesToTry[i],
- &memoryRequirements,
- memoryRequirements.size,
- false,
- VK_NULL_HANDLE,
- image,
- usedRegion);
- if (bindResult == 1) {
- selectedMemoryTypeIndex = memoryTypesToTry[i];
- break;
- }
- }
- SDL_free(memoryTypesToTry);
- // Check for warnings on success
- if (bindResult == 1) {
- if (!renderer->outOfDeviceLocalMemoryWarning) {
- if ((renderer->memoryProperties.memoryTypes[selectedMemoryTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == 0) {
- SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Out of device-local memory, allocating textures on host-local memory!");
- renderer->outOfDeviceLocalMemoryWarning = 1;
- }
- }
- }
- return bindResult;
- }
- static Uint8 VULKAN_INTERNAL_BindMemoryForBuffer(
- VulkanRenderer *renderer,
- VkBuffer buffer,
- VkDeviceSize size,
- VulkanBufferType type,
- bool dedicated,
- VulkanMemoryUsedRegion **usedRegion)
- {
- Uint8 bindResult = 0;
- Uint32 memoryTypeCount = 0;
- Uint32 *memoryTypesToTry = NULL;
- Uint32 selectedMemoryTypeIndex = 0;
- Uint32 i;
- VkMemoryPropertyFlags requiredMemoryPropertyFlags = 0;
- VkMemoryPropertyFlags preferredMemoryPropertyFlags = 0;
- VkMemoryPropertyFlags tolerableMemoryPropertyFlags = 0;
- VkMemoryRequirements memoryRequirements;
- /* Buffers need to be optimally bound to a memory type
- * based on their use case and the architecture of the system.
- *
- * It is important to understand the distinction between device and host.
- *
- * On a traditional high-performance desktop computer,
- * the "device" would be the GPU, and the "host" would be the CPU.
- * Memory being copied between these two must cross the PCI bus.
- * On these systems we have to be concerned about bandwidth limitations
- * and causing memory stalls, so we have taken a great deal of care
- * to structure this API to guide the client towards optimal usage.
- *
- * Other kinds of devices do not necessarily have this distinction.
- * On an iPhone or Nintendo Switch, all memory is accessible both to the
- * GPU and the CPU at all times. These kinds of systems are known as
- * UMA, or Unified Memory Architecture. A desktop computer using the
- * CPU's integrated graphics can also be thought of as UMA.
- *
- * Vulkan memory types have several memory properties.
- * The relevant memory properties are as follows:
- *
- * DEVICE_LOCAL:
- * This memory is on-device and most efficient for device access.
- * On UMA systems all memory is device-local.
- * If memory is not device-local, then it is host-local.
- *
- * HOST_VISIBLE:
- * This memory can be mapped for host access, meaning we can obtain
- * a pointer to directly access the memory.
- *
- * HOST_COHERENT:
- * Host-coherent memory does not require cache management operations
- * when mapped, so we always set this alongside HOST_VISIBLE
- * to avoid extra record keeping.
- *
- * HOST_CACHED:
- * Host-cached memory is faster to access than uncached memory
- * but memory of this type might not always be available.
- *
- * GPU buffers, like vertex buffers, indirect buffers, etc
- * are optimally stored in device-local memory.
- * However, if device-local memory is low, these buffers
- * can be accessed from host-local memory with a performance penalty.
- *
- * Uniform buffers must be host-visible and coherent because
- * the client uses them to quickly push small amounts of data.
- * We prefer uniform buffers to also be device-local because
- * they are accessed by shaders, but the amount of memory
- * that is both device-local and host-visible
- * is often constrained, particularly on low-end devices.
- *
- * Transfer buffers must be host-visible and coherent because
- * the client uses them to stage data to be transferred
- * to device-local memory, or to read back data transferred
- * from the device. We prefer the cache bit for performance
- * but it isn't strictly necessary. We tolerate device-local
- * memory in this situation because, as mentioned above,
- * on certain devices all memory is device-local, and even
- * though the transfer isn't strictly necessary it is still
- * useful for correctly timelining data.
- */
- if (type == VULKAN_BUFFER_TYPE_GPU) {
- preferredMemoryPropertyFlags |=
- VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
- } else if (type == VULKAN_BUFFER_TYPE_UNIFORM) {
- requiredMemoryPropertyFlags |=
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
- VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
- preferredMemoryPropertyFlags |=
- VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
- } else if (type == VULKAN_BUFFER_TYPE_TRANSFER) {
- requiredMemoryPropertyFlags |=
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
- VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
- preferredMemoryPropertyFlags |=
- VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
- tolerableMemoryPropertyFlags |=
- VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
- } else {
- SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized buffer type!");
- return 0;
- }
- memoryTypesToTry = VULKAN_INTERNAL_FindBestBufferMemoryTypes(
- renderer,
- buffer,
- requiredMemoryPropertyFlags,
- preferredMemoryPropertyFlags,
- tolerableMemoryPropertyFlags,
- &memoryRequirements,
- &memoryTypeCount);
- for (i = 0; i < memoryTypeCount; i += 1) {
- bindResult = VULKAN_INTERNAL_BindResourceMemory(
- renderer,
- memoryTypesToTry[i],
- &memoryRequirements,
- size,
- dedicated,
- buffer,
- VK_NULL_HANDLE,
- usedRegion);
- if (bindResult == 1) {
- selectedMemoryTypeIndex = memoryTypesToTry[i];
- break;
- }
- }
- SDL_free(memoryTypesToTry);
- // Check for warnings on success
- if (bindResult == 1) {
- if (type == VULKAN_BUFFER_TYPE_GPU) {
- if (!renderer->outOfDeviceLocalMemoryWarning) {
- if ((renderer->memoryProperties.memoryTypes[selectedMemoryTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == 0) {
- SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Out of device-local memory, allocating buffers on host-local memory, expect degraded performance!");
- renderer->outOfDeviceLocalMemoryWarning = 1;
- }
- }
- } else if (type == VULKAN_BUFFER_TYPE_UNIFORM) {
- if (!renderer->outofBARMemoryWarning) {
- if ((renderer->memoryProperties.memoryTypes[selectedMemoryTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == 0) {
- SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Out of BAR memory, allocating uniform buffers on host-local memory, expect degraded performance!");
- renderer->outofBARMemoryWarning = 1;
- }
- }
- } else if (type == VULKAN_BUFFER_TYPE_TRANSFER) {
- if (!renderer->integratedMemoryNotification) {
- if ((renderer->memoryProperties.memoryTypes[selectedMemoryTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
- SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Integrated memory detected, allocating TransferBuffers on device-local memory!");
- renderer->integratedMemoryNotification = 1;
- }
- }
- }
- }
- return bindResult;
- }
- // Resource tracking
- #define TRACK_RESOURCE(resource, type, array, count, capacity) \
- for (Sint32 i = commandBuffer->count - 1; i >= 0; i -= 1) { \
- if (commandBuffer->array[i] == resource) { \
- return; \
- } \
- } \
- \
- if (commandBuffer->count == commandBuffer->capacity) { \
- commandBuffer->capacity += 1; \
- commandBuffer->array = SDL_realloc( \
- commandBuffer->array, \
- commandBuffer->capacity * sizeof(type)); \
- } \
- commandBuffer->array[commandBuffer->count] = resource; \
- commandBuffer->count += 1; \
- SDL_AtomicIncRef(&resource->referenceCount);
- static void VULKAN_INTERNAL_TrackBuffer(
- VulkanCommandBuffer *commandBuffer,
- VulkanBuffer *buffer)
- {
- TRACK_RESOURCE(
- buffer,
- VulkanBuffer *,
- usedBuffers,
- usedBufferCount,
- usedBufferCapacity)
- }
- static void VULKAN_INTERNAL_TrackTexture(
- VulkanCommandBuffer *commandBuffer,
- VulkanTexture *texture)
- {
- TRACK_RESOURCE(
- texture,
- VulkanTexture *,
- usedTextures,
- usedTextureCount,
- usedTextureCapacity)
- }
- static void VULKAN_INTERNAL_TrackSampler(
- VulkanCommandBuffer *commandBuffer,
- VulkanSampler *sampler)
- {
- TRACK_RESOURCE(
- sampler,
- VulkanSampler *,
- usedSamplers,
- usedSamplerCount,
- usedSamplerCapacity)
- }
- static void VULKAN_INTERNAL_TrackGraphicsPipeline(
- VulkanCommandBuffer *commandBuffer,
- VulkanGraphicsPipeline *graphicsPipeline)
- {
- TRACK_RESOURCE(
- graphicsPipeline,
- VulkanGraphicsPipeline *,
- usedGraphicsPipelines,
- usedGraphicsPipelineCount,
- usedGraphicsPipelineCapacity)
- }
- static void VULKAN_INTERNAL_TrackComputePipeline(
- VulkanCommandBuffer *commandBuffer,
- VulkanComputePipeline *computePipeline)
- {
- TRACK_RESOURCE(
- computePipeline,
- VulkanComputePipeline *,
- usedComputePipelines,
- usedComputePipelineCount,
- usedComputePipelineCapacity)
- }
- static void VULKAN_INTERNAL_TrackFramebuffer(
- VulkanCommandBuffer *commandBuffer,
- VulkanFramebuffer *framebuffer)
- {
- TRACK_RESOURCE(
- framebuffer,
- VulkanFramebuffer *,
- usedFramebuffers,
- usedFramebufferCount,
- usedFramebufferCapacity);
- }
- static void VULKAN_INTERNAL_TrackUniformBuffer(
- VulkanCommandBuffer *commandBuffer,
- VulkanUniformBuffer *uniformBuffer)
- {
- for (Sint32 i = commandBuffer->usedUniformBufferCount - 1; i >= 0; i -= 1) {
- if (commandBuffer->usedUniformBuffers[i] == uniformBuffer) {
- return;
- }
- }
- if (commandBuffer->usedUniformBufferCount == commandBuffer->usedUniformBufferCapacity) {
- commandBuffer->usedUniformBufferCapacity += 1;
- commandBuffer->usedUniformBuffers = SDL_realloc(
- commandBuffer->usedUniformBuffers,
- commandBuffer->usedUniformBufferCapacity * sizeof(VulkanUniformBuffer *));
- }
- commandBuffer->usedUniformBuffers[commandBuffer->usedUniformBufferCount] = uniformBuffer;
- commandBuffer->usedUniformBufferCount += 1;
- VULKAN_INTERNAL_TrackBuffer(
- commandBuffer,
- uniformBuffer->buffer);
- }
- #undef TRACK_RESOURCE
- // Memory Barriers
- /*
- * In Vulkan, we must manually synchronize operations that write to resources on the GPU
- * so that read-after-write, write-after-read, and write-after-write hazards do not occur.
- * Additionally, textures are required to be in specific layouts for specific use cases.
- * Both of these tasks are accomplished with vkCmdPipelineBarrier.
- *
- * To insert the correct barriers, we keep track of "usage modes" for buffers and textures.
- * These indicate the current usage of that resource on the command buffer.
- * The transition from one usage mode to another indicates how the barrier should be constructed.
- *
- * Pipeline barriers cannot be inserted during a render pass, but they can be inserted
- * during a compute or copy pass.
- *
- * This means that the "default" usage mode of any given resource should be that it should be
- * ready for a graphics-read operation, because we cannot barrier during a render pass.
- * In the case where a resource is only used in compute, its default usage mode can be compute-read.
- * This strategy allows us to avoid expensive record keeping of command buffer/resource usage mode pairs,
- * and it fully covers synchronization between all combinations of stages.
- *
- * In Upload and Copy functions, we transition the resource immediately before and after the copy command.
- *
- * When binding a resource for compute, we transition when the Bind functions are called.
- * If a bind slot containing a resource is overwritten, we transition the resource in that slot back to its default.
- * When EndComputePass is called we transition all bound resources back to their default state.
- *
- * When binding a texture as a render pass attachment, we transition the resource on BeginRenderPass
- * and transition it back to its default on EndRenderPass.
- *
- * This strategy imposes certain limitations on resource usage flags.
- * For example, a texture cannot have both the SAMPLER and GRAPHICS_STORAGE usage flags,
- * because then it is impossible for the backend to infer which default usage mode the texture should use.
- *
- * Sync hazards can be detected by setting VK_KHRONOS_VALIDATION_VALIDATE_SYNC=1 when using validation layers.
- */
- static void VULKAN_INTERNAL_BufferMemoryBarrier(
- VulkanRenderer *renderer,
- VulkanCommandBuffer *commandBuffer,
- VulkanBufferUsageMode sourceUsageMode,
- VulkanBufferUsageMode destinationUsageMode,
- VulkanBuffer *buffer)
- {
- VkPipelineStageFlags srcStages = 0;
- VkPipelineStageFlags dstStages = 0;
- VkBufferMemoryBarrier memoryBarrier;
- memoryBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
- memoryBarrier.pNext = NULL;
- memoryBarrier.srcAccessMask = 0;
- memoryBarrier.dstAccessMask = 0;
- memoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- memoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- memoryBarrier.buffer = buffer->buffer;
- memoryBarrier.offset = 0;
- memoryBarrier.size = buffer->size;
- if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE) {
- srcStages = VK_PIPELINE_STAGE_TRANSFER_BIT;
- memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
- } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION) {
- srcStages = VK_PIPELINE_STAGE_TRANSFER_BIT;
- memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
- } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_VERTEX_READ) {
- srcStages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
- memoryBarrier.srcAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
- } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_INDEX_READ) {
- srcStages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
- memoryBarrier.srcAccessMask = VK_ACCESS_INDEX_READ_BIT;
- } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_INDIRECT) {
- srcStages = VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
- memoryBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
- } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_GRAPHICS_STORAGE_READ) {
- srcStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
- memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
- } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ) {
- srcStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
- memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
- } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE) {
- srcStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
- memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
- } else {
- SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized buffer source barrier type!");
- return;
- }
- if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE) {
- dstStages = VK_PIPELINE_STAGE_TRANSFER_BIT;
- memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
- } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION) {
- dstStages = VK_PIPELINE_STAGE_TRANSFER_BIT;
- memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
- } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_VERTEX_READ) {
- dstStages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
- memoryBarrier.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
- } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_INDEX_READ) {
- dstStages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
- memoryBarrier.dstAccessMask = VK_ACCESS_INDEX_READ_BIT;
- } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_INDIRECT) {
- dstStages = VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
- memoryBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
- } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_GRAPHICS_STORAGE_READ) {
- dstStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
- memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
- } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ) {
- dstStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
- memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
- } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE) {
- dstStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
- memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
- } else {
- SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized buffer destination barrier type!");
- return;
- }
- renderer->vkCmdPipelineBarrier(
- commandBuffer->commandBuffer,
- srcStages,
- dstStages,
- 0,
- 0,
- NULL,
- 1,
- &memoryBarrier,
- 0,
- NULL);
- buffer->transitioned = true;
- }
- static void VULKAN_INTERNAL_TextureSubresourceMemoryBarrier(
- VulkanRenderer *renderer,
- VulkanCommandBuffer *commandBuffer,
- VulkanTextureUsageMode sourceUsageMode,
- VulkanTextureUsageMode destinationUsageMode,
- VulkanTextureSubresource *textureSubresource)
- {
- VkPipelineStageFlags srcStages = 0;
- VkPipelineStageFlags dstStages = 0;
- VkImageMemoryBarrier memoryBarrier;
- memoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- memoryBarrier.pNext = NULL;
- memoryBarrier.srcAccessMask = 0;
- memoryBarrier.dstAccessMask = 0;
- memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- memoryBarrier.newLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- memoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- memoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- memoryBarrier.image = textureSubresource->parent->image;
- memoryBarrier.subresourceRange.aspectMask = textureSubresource->parent->aspectFlags;
- memoryBarrier.subresourceRange.baseArrayLayer = textureSubresource->layer;
- memoryBarrier.subresourceRange.layerCount = 1;
- memoryBarrier.subresourceRange.baseMipLevel = textureSubresource->level;
- memoryBarrier.subresourceRange.levelCount = 1;
- if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED) {
- srcStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
- memoryBarrier.srcAccessMask = 0;
- memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE) {
- srcStages = VK_PIPELINE_STAGE_TRANSFER_BIT;
- memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
- memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
- } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION) {
- srcStages = VK_PIPELINE_STAGE_TRANSFER_BIT;
- memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
- memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
- } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_SAMPLER) {
- srcStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
- memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
- memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_GRAPHICS_STORAGE_READ) {
- srcStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
- memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
- memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
- } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ) {
- srcStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
- memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
- memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
- } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE) {
- srcStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
- memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
- memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
- } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT) {
- srcStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- memoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
- memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_DEPTH_STENCIL_ATTACHMENT) {
- srcStages = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
- memoryBarrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
- memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
- } else {
- SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized texture source barrier type!");
- return;
- }
- if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE) {
- dstStages = VK_PIPELINE_STAGE_TRANSFER_BIT;
- memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
- memoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
- } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION) {
- dstStages = VK_PIPELINE_STAGE_TRANSFER_BIT;
- memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
- memoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
- } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_SAMPLER) {
- dstStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
- memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
- memoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_GRAPHICS_STORAGE_READ) {
- dstStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
- memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
- memoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
- } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ) {
- dstStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
- memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
- memoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
- } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE) {
- dstStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
- memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
- memoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
- } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT) {
- dstStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- memoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
- memoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_DEPTH_STENCIL_ATTACHMENT) {
- dstStages = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
- memoryBarrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
- memoryBarrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
- } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_PRESENT) {
- dstStages = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
- memoryBarrier.dstAccessMask = 0;
- memoryBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
- } else {
- SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized texture destination barrier type!");
- return;
- }
- renderer->vkCmdPipelineBarrier(
- commandBuffer->commandBuffer,
- srcStages,
- dstStages,
- 0,
- 0,
- NULL,
- 0,
- NULL,
- 1,
- &memoryBarrier);
- }
- static VulkanBufferUsageMode VULKAN_INTERNAL_DefaultBufferUsageMode(
- VulkanBuffer *buffer)
- {
- // NOTE: order matters here!
- if (buffer->usage & SDL_GPU_BUFFERUSAGE_VERTEX) {
- return VULKAN_BUFFER_USAGE_MODE_VERTEX_READ;
- } else if (buffer->usage & SDL_GPU_BUFFERUSAGE_INDEX) {
- return VULKAN_BUFFER_USAGE_MODE_INDEX_READ;
- } else if (buffer->usage & SDL_GPU_BUFFERUSAGE_INDIRECT) {
- return VULKAN_BUFFER_USAGE_MODE_INDIRECT;
- } else if (buffer->usage & SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ) {
- return VULKAN_BUFFER_USAGE_MODE_GRAPHICS_STORAGE_READ;
- } else if (buffer->usage & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_READ) {
- return VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ;
- } else if (buffer->usage & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE) {
- return VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE;
- } else {
- SDL_LogError(SDL_LOG_CATEGORY_GPU, "Buffer has no default usage mode!");
- return VULKAN_BUFFER_USAGE_MODE_VERTEX_READ;
- }
- }
- static VulkanTextureUsageMode VULKAN_INTERNAL_DefaultTextureUsageMode(
- VulkanTexture *texture)
- {
- // NOTE: order matters here!
- // NOTE: graphics storage bits and sampler bit are mutually exclusive!
- if (texture->usage & SDL_GPU_TEXTUREUSAGE_SAMPLER) {
- return VULKAN_TEXTURE_USAGE_MODE_SAMPLER;
- } else if (texture->usage & SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ) {
- return VULKAN_TEXTURE_USAGE_MODE_GRAPHICS_STORAGE_READ;
- } else if (texture->usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) {
- return VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT;
- } else if (texture->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) {
- return VULKAN_TEXTURE_USAGE_MODE_DEPTH_STENCIL_ATTACHMENT;
- } else if (texture->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ) {
- return VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ;
- } else if (texture->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) {
- return VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE;
- } else if (texture->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE) {
- return VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE;
- } else {
- SDL_LogError(SDL_LOG_CATEGORY_GPU, "Texture has no default usage mode!");
- return VULKAN_TEXTURE_USAGE_MODE_SAMPLER;
- }
- }
- static void VULKAN_INTERNAL_BufferTransitionFromDefaultUsage(
- VulkanRenderer *renderer,
- VulkanCommandBuffer *commandBuffer,
- VulkanBufferUsageMode destinationUsageMode,
- VulkanBuffer *buffer)
- {
- VULKAN_INTERNAL_BufferMemoryBarrier(
- renderer,
- commandBuffer,
- VULKAN_INTERNAL_DefaultBufferUsageMode(buffer),
- destinationUsageMode,
- buffer);
- }
- static void VULKAN_INTERNAL_BufferTransitionToDefaultUsage(
- VulkanRenderer *renderer,
- VulkanCommandBuffer *commandBuffer,
- VulkanBufferUsageMode sourceUsageMode,
- VulkanBuffer *buffer)
- {
- VULKAN_INTERNAL_BufferMemoryBarrier(
- renderer,
- commandBuffer,
- sourceUsageMode,
- VULKAN_INTERNAL_DefaultBufferUsageMode(buffer),
- buffer);
- }
- static void VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage(
- VulkanRenderer *renderer,
- VulkanCommandBuffer *commandBuffer,
- VulkanTextureUsageMode destinationUsageMode,
- VulkanTextureSubresource *textureSubresource)
- {
- VULKAN_INTERNAL_TextureSubresourceMemoryBarrier(
- renderer,
- commandBuffer,
- VULKAN_INTERNAL_DefaultTextureUsageMode(textureSubresource->parent),
- destinationUsageMode,
- textureSubresource);
- }
- static void VULKAN_INTERNAL_TextureTransitionFromDefaultUsage(
- VulkanRenderer *renderer,
- VulkanCommandBuffer *commandBuffer,
- VulkanTextureUsageMode destinationUsageMode,
- VulkanTexture *texture)
- {
- for (Uint32 i = 0; i < texture->subresourceCount; i += 1) {
- VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage(
- renderer,
- commandBuffer,
- destinationUsageMode,
- &texture->subresources[i]);
- }
- }
- static void VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
- VulkanRenderer *renderer,
- VulkanCommandBuffer *commandBuffer,
- VulkanTextureUsageMode sourceUsageMode,
- VulkanTextureSubresource *textureSubresource)
- {
- VULKAN_INTERNAL_TextureSubresourceMemoryBarrier(
- renderer,
- commandBuffer,
- sourceUsageMode,
- VULKAN_INTERNAL_DefaultTextureUsageMode(textureSubresource->parent),
- textureSubresource);
- }
- static void VULKAN_INTERNAL_TextureTransitionToDefaultUsage(
- VulkanRenderer *renderer,
- VulkanCommandBuffer *commandBuffer,
- VulkanTextureUsageMode sourceUsageMode,
- VulkanTexture *texture)
- {
- // FIXME: could optimize this barrier
- for (Uint32 i = 0; i < texture->subresourceCount; i += 1) {
- VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
- renderer,
- commandBuffer,
- sourceUsageMode,
- &texture->subresources[i]);
- }
- }
- // Resource Disposal
- static void VULKAN_INTERNAL_ReleaseFramebuffer(
- VulkanRenderer *renderer,
- VulkanFramebuffer *framebuffer)
- {
- SDL_LockMutex(renderer->disposeLock);
- EXPAND_ARRAY_IF_NEEDED(
- renderer->framebuffersToDestroy,
- VulkanFramebuffer *,
- renderer->framebuffersToDestroyCount + 1,
- renderer->framebuffersToDestroyCapacity,
- renderer->framebuffersToDestroyCapacity * 2);
- renderer->framebuffersToDestroy[renderer->framebuffersToDestroyCount] = framebuffer;
- renderer->framebuffersToDestroyCount += 1;
- SDL_UnlockMutex(renderer->disposeLock);
- }
- static void VULKAN_INTERNAL_DestroyFramebuffer(
- VulkanRenderer *renderer,
- VulkanFramebuffer *framebuffer)
- {
- renderer->vkDestroyFramebuffer(
- renderer->logicalDevice,
- framebuffer->framebuffer,
- NULL);
- SDL_free(framebuffer);
- }
- typedef struct CheckOneFramebufferForRemovalData
- {
- Uint32 keysToRemoveCapacity;
- Uint32 keysToRemoveCount;
- FramebufferHashTableKey **keysToRemove;
- VkImageView view;
- } CheckOneFramebufferForRemovalData;
- static bool SDLCALL CheckOneFramebufferForRemoval(void *userdata, const SDL_HashTable *table, const void *vkey, const void *vvalue)
- {
- CheckOneFramebufferForRemovalData *data = (CheckOneFramebufferForRemovalData *) userdata;
- FramebufferHashTableKey *key = (FramebufferHashTableKey *) vkey;
- VkImageView view = data->view;
- bool remove = false;
- for (Uint32 i = 0; i < key->numColorTargets; i += 1) {
- if (key->colorAttachmentViews[i] == view) {
- remove = true;
- }
- }
- for (Uint32 i = 0; i < key->numResolveAttachments; i += 1) {
- if (key->resolveAttachmentViews[i] == view) {
- remove = true;
- }
- }
- if (key->depthStencilAttachmentView == view) {
- remove = true;
- }
- if (remove) {
- if (data->keysToRemoveCount == data->keysToRemoveCapacity) {
- data->keysToRemoveCapacity *= 2;
- void *ptr = SDL_realloc(data->keysToRemove, data->keysToRemoveCapacity * sizeof(FramebufferHashTableKey *));
- if (!ptr) {
- return false; // ugh, stop iterating. We're in trouble.
- }
- data->keysToRemove = (FramebufferHashTableKey **) ptr;
- }
- data->keysToRemove[data->keysToRemoveCount] = key;
- data->keysToRemoveCount++;
- }
- return true; // keep iterating.
- }
- static void VULKAN_INTERNAL_RemoveFramebuffersContainingView(
- VulkanRenderer *renderer,
- VkImageView view)
- {
- // Can't remove while iterating!
- CheckOneFramebufferForRemovalData data = { 8, 0, NULL, view };
- data.keysToRemove = (FramebufferHashTableKey **) SDL_malloc(data.keysToRemoveCapacity * sizeof(FramebufferHashTableKey *));
- if (!data.keysToRemove) {
- return; // uhoh.
- }
- SDL_LockMutex(renderer->framebufferFetchLock);
- SDL_IterateHashTable(renderer->framebufferHashTable, CheckOneFramebufferForRemoval, &data);
- for (Uint32 i = 0; i < data.keysToRemoveCount; i += 1) {
- SDL_RemoveFromHashTable(renderer->framebufferHashTable, (void *)data.keysToRemove[i]);
- }
- SDL_UnlockMutex(renderer->framebufferFetchLock);
- SDL_free(data.keysToRemove);
- }
- static void VULKAN_INTERNAL_DestroyTexture(
- VulkanRenderer *renderer,
- VulkanTexture *texture)
- {
- // Clean up subresources
- for (Uint32 subresourceIndex = 0; subresourceIndex < texture->subresourceCount; subresourceIndex += 1) {
- if (texture->subresources[subresourceIndex].renderTargetViews != NULL) {
- for (Uint32 depthIndex = 0; depthIndex < texture->depth; depthIndex += 1) {
- VULKAN_INTERNAL_RemoveFramebuffersContainingView(
- renderer,
- texture->subresources[subresourceIndex].renderTargetViews[depthIndex]);
- }
- for (Uint32 depthIndex = 0; depthIndex < texture->depth; depthIndex += 1) {
- renderer->vkDestroyImageView(
- renderer->logicalDevice,
- texture->subresources[subresourceIndex].renderTargetViews[depthIndex],
- NULL);
- }
- SDL_free(texture->subresources[subresourceIndex].renderTargetViews);
- }
- if (texture->subresources[subresourceIndex].computeWriteView != VK_NULL_HANDLE) {
- renderer->vkDestroyImageView(
- renderer->logicalDevice,
- texture->subresources[subresourceIndex].computeWriteView,
- NULL);
- }
- if (texture->subresources[subresourceIndex].depthStencilView != VK_NULL_HANDLE) {
- VULKAN_INTERNAL_RemoveFramebuffersContainingView(
- renderer,
- texture->subresources[subresourceIndex].depthStencilView);
- renderer->vkDestroyImageView(
- renderer->logicalDevice,
- texture->subresources[subresourceIndex].depthStencilView,
- NULL);
- }
- }
- SDL_free(texture->subresources);
- if (texture->fullView) {
- renderer->vkDestroyImageView(
- renderer->logicalDevice,
- texture->fullView,
- NULL);
- }
- if (texture->image) {
- renderer->vkDestroyImage(
- renderer->logicalDevice,
- texture->image,
- NULL);
- }
- if (texture->usedRegion) {
- VULKAN_INTERNAL_RemoveMemoryUsedRegion(
- renderer,
- texture->usedRegion);
- }
- SDL_free(texture);
- }
- static void VULKAN_INTERNAL_DestroyBuffer(
- VulkanRenderer *renderer,
- VulkanBuffer *buffer)
- {
- renderer->vkDestroyBuffer(
- renderer->logicalDevice,
- buffer->buffer,
- NULL);
- VULKAN_INTERNAL_RemoveMemoryUsedRegion(
- renderer,
- buffer->usedRegion);
- SDL_free(buffer);
- }
- static void VULKAN_INTERNAL_DestroyCommandPool(
- VulkanRenderer *renderer,
- VulkanCommandPool *commandPool)
- {
- Uint32 i;
- VulkanCommandBuffer *commandBuffer;
- renderer->vkDestroyCommandPool(
- renderer->logicalDevice,
- commandPool->commandPool,
- NULL);
- for (i = 0; i < commandPool->inactiveCommandBufferCount; i += 1) {
- commandBuffer = commandPool->inactiveCommandBuffers[i];
- SDL_free(commandBuffer->presentDatas);
- SDL_free(commandBuffer->waitSemaphores);
- SDL_free(commandBuffer->signalSemaphores);
- SDL_free(commandBuffer->usedBuffers);
- SDL_free(commandBuffer->usedTextures);
- SDL_free(commandBuffer->usedSamplers);
- SDL_free(commandBuffer->usedGraphicsPipelines);
- SDL_free(commandBuffer->usedComputePipelines);
- SDL_free(commandBuffer->usedFramebuffers);
- SDL_free(commandBuffer->usedUniformBuffers);
- SDL_free(commandBuffer);
- }
- SDL_free(commandPool->inactiveCommandBuffers);
- SDL_free(commandPool);
- }
- static void VULKAN_INTERNAL_DestroyDescriptorSetLayout(
- VulkanRenderer *renderer,
- DescriptorSetLayout *layout)
- {
- if (layout == NULL) {
- return;
- }
- if (layout->descriptorSetLayout != VK_NULL_HANDLE) {
- renderer->vkDestroyDescriptorSetLayout(
- renderer->logicalDevice,
- layout->descriptorSetLayout,
- NULL);
- }
- SDL_free(layout);
- }
- static void VULKAN_INTERNAL_DestroyGraphicsPipeline(
- VulkanRenderer *renderer,
- VulkanGraphicsPipeline *graphicsPipeline)
- {
- renderer->vkDestroyPipeline(
- renderer->logicalDevice,
- graphicsPipeline->pipeline,
- NULL);
- (void)SDL_AtomicDecRef(&graphicsPipeline->vertexShader->referenceCount);
- (void)SDL_AtomicDecRef(&graphicsPipeline->fragmentShader->referenceCount);
- SDL_free(graphicsPipeline);
- }
- static void VULKAN_INTERNAL_DestroyComputePipeline(
- VulkanRenderer *renderer,
- VulkanComputePipeline *computePipeline)
- {
- if (computePipeline->pipeline != VK_NULL_HANDLE) {
- renderer->vkDestroyPipeline(
- renderer->logicalDevice,
- computePipeline->pipeline,
- NULL);
- }
- if (computePipeline->shaderModule != VK_NULL_HANDLE) {
- renderer->vkDestroyShaderModule(
- renderer->logicalDevice,
- computePipeline->shaderModule,
- NULL);
- }
- SDL_free(computePipeline);
- }
- static void VULKAN_INTERNAL_DestroyShader(
- VulkanRenderer *renderer,
- VulkanShader *vulkanShader)
- {
- renderer->vkDestroyShaderModule(
- renderer->logicalDevice,
- vulkanShader->shaderModule,
- NULL);
- SDL_free(vulkanShader->entrypointName);
- SDL_free(vulkanShader);
- }
- static void VULKAN_INTERNAL_DestroySampler(
- VulkanRenderer *renderer,
- VulkanSampler *vulkanSampler)
- {
- renderer->vkDestroySampler(
- renderer->logicalDevice,
- vulkanSampler->sampler,
- NULL);
- SDL_free(vulkanSampler);
- }
- static void VULKAN_INTERNAL_DestroySwapchainImage(
- VulkanRenderer *renderer,
- WindowData *windowData)
- {
- Uint32 i;
- if (windowData == NULL) {
- return;
- }
- for (i = 0; i < windowData->imageCount; i += 1) {
- VULKAN_INTERNAL_RemoveFramebuffersContainingView(
- renderer,
- windowData->textureContainers[i].activeTexture->subresources[0].renderTargetViews[0]);
- renderer->vkDestroyImageView(
- renderer->logicalDevice,
- windowData->textureContainers[i].activeTexture->subresources[0].renderTargetViews[0],
- NULL);
- SDL_free(windowData->textureContainers[i].activeTexture->subresources[0].renderTargetViews);
- SDL_free(windowData->textureContainers[i].activeTexture->subresources);
- SDL_free(windowData->textureContainers[i].activeTexture);
- }
- SDL_free(windowData->textureContainers);
- windowData->textureContainers = NULL;
- for (i = 0; i < MAX_FRAMES_IN_FLIGHT; i += 1) {
- if (windowData->imageAvailableSemaphore[i]) {
- renderer->vkDestroySemaphore(
- renderer->logicalDevice,
- windowData->imageAvailableSemaphore[i],
- NULL);
- windowData->imageAvailableSemaphore[i] = VK_NULL_HANDLE;
- }
- }
- for (i = 0; i < windowData->imageCount; i += 1) {
- if (windowData->renderFinishedSemaphore[i]) {
- renderer->vkDestroySemaphore(
- renderer->logicalDevice,
- windowData->renderFinishedSemaphore[i],
- NULL);
- windowData->renderFinishedSemaphore[i] = VK_NULL_HANDLE;
- }
- }
- SDL_free(windowData->renderFinishedSemaphore);
- windowData->renderFinishedSemaphore = NULL;
- windowData->imageCount = 0;
- }
- static void VULKAN_INTERNAL_DestroySwapchain(
- VulkanRenderer *renderer,
- WindowData *windowData)
- {
- if (windowData == NULL) {
- return;
- }
- VULKAN_INTERNAL_DestroySwapchainImage(renderer, windowData);
- if (windowData->swapchain) {
- renderer->vkDestroySwapchainKHR(
- renderer->logicalDevice,
- windowData->swapchain,
- NULL);
- windowData->swapchain = VK_NULL_HANDLE;
- }
- }
- static void VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout(
- VulkanRenderer *renderer,
- VulkanGraphicsPipelineResourceLayout *resourceLayout)
- {
- if (resourceLayout->pipelineLayout != VK_NULL_HANDLE) {
- renderer->vkDestroyPipelineLayout(
- renderer->logicalDevice,
- resourceLayout->pipelineLayout,
- NULL);
- }
- SDL_free(resourceLayout);
- }
- static void VULKAN_INTERNAL_DestroyComputePipelineResourceLayout(
- VulkanRenderer *renderer,
- VulkanComputePipelineResourceLayout *resourceLayout)
- {
- if (resourceLayout->pipelineLayout != VK_NULL_HANDLE) {
- renderer->vkDestroyPipelineLayout(
- renderer->logicalDevice,
- resourceLayout->pipelineLayout,
- NULL);
- }
- SDL_free(resourceLayout);
- }
- static void VULKAN_INTERNAL_DestroyDescriptorSetCache(
- VulkanRenderer *renderer,
- DescriptorSetCache *descriptorSetCache)
- {
- for (Uint32 i = 0; i < descriptorSetCache->poolCount; i += 1) {
- for (Uint32 j = 0; j < descriptorSetCache->pools[i].poolCount; j += 1) {
- renderer->vkDestroyDescriptorPool(
- renderer->logicalDevice,
- descriptorSetCache->pools[i].descriptorPools[j],
- NULL);
- }
- SDL_free(descriptorSetCache->pools[i].descriptorSets);
- SDL_free(descriptorSetCache->pools[i].descriptorPools);
- }
- SDL_free(descriptorSetCache->pools);
- SDL_free(descriptorSetCache);
- }
- // Hashtable functions
- static Uint32 SDLCALL VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashFunction(void *userdata, const void *key)
- {
- GraphicsPipelineResourceLayoutHashTableKey *hashTableKey = (GraphicsPipelineResourceLayoutHashTableKey *)key;
- /* The algorithm for this hashing function
- * is taken from Josh Bloch's "Effective Java".
- * (https://stackoverflow.com/a/113600/12492383)
- */
- const Uint32 hashFactor = 31;
- Uint32 result = 1;
- result = result * hashFactor + hashTableKey->vertexSamplerCount;
- result = result * hashFactor + hashTableKey->vertexStorageBufferCount;
- result = result * hashFactor + hashTableKey->vertexStorageTextureCount;
- result = result * hashFactor + hashTableKey->vertexUniformBufferCount;
- result = result * hashFactor + hashTableKey->fragmentSamplerCount;
- result = result * hashFactor + hashTableKey->fragmentStorageBufferCount;
- result = result * hashFactor + hashTableKey->fragmentStorageTextureCount;
- result = result * hashFactor + hashTableKey->fragmentUniformBufferCount;
- return result;
- }
- static bool SDLCALL VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashKeyMatch(void *userdata, const void *aKey, const void *bKey)
- {
- return SDL_memcmp(aKey, bKey, sizeof(GraphicsPipelineResourceLayoutHashTableKey)) == 0;
- }
- static void SDLCALL VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashDestroy(void *userdata, const void *key, const void *value)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)userdata;
- VulkanGraphicsPipelineResourceLayout *resourceLayout = (VulkanGraphicsPipelineResourceLayout *)value;
- VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout(renderer, resourceLayout);
- SDL_free((void *)key);
- }
- static Uint32 SDLCALL VULKAN_INTERNAL_ComputePipelineResourceLayoutHashFunction(void *userdata, const void *key)
- {
- ComputePipelineResourceLayoutHashTableKey *hashTableKey = (ComputePipelineResourceLayoutHashTableKey *)key;
- /* The algorithm for this hashing function
- * is taken from Josh Bloch's "Effective Java".
- * (https://stackoverflow.com/a/113600/12492383)
- */
- const Uint32 hashFactor = 31;
- Uint32 result = 1;
- result = result * hashFactor + hashTableKey->samplerCount;
- result = result * hashFactor + hashTableKey->readonlyStorageTextureCount;
- result = result * hashFactor + hashTableKey->readonlyStorageBufferCount;
- result = result * hashFactor + hashTableKey->readWriteStorageTextureCount;
- result = result * hashFactor + hashTableKey->readWriteStorageBufferCount;
- result = result * hashFactor + hashTableKey->uniformBufferCount;
- return result;
- }
- static bool SDLCALL VULKAN_INTERNAL_ComputePipelineResourceLayoutHashKeyMatch(void *userdata, const void *aKey, const void *bKey)
- {
- return SDL_memcmp(aKey, bKey, sizeof(ComputePipelineResourceLayoutHashTableKey)) == 0;
- }
- static void SDLCALL VULKAN_INTERNAL_ComputePipelineResourceLayoutHashDestroy(void *userdata, const void *key, const void *value)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)userdata;
- VulkanComputePipelineResourceLayout *resourceLayout = (VulkanComputePipelineResourceLayout *)value;
- VULKAN_INTERNAL_DestroyComputePipelineResourceLayout(renderer, resourceLayout);
- SDL_free((void *)key);
- }
- static Uint32 SDLCALL VULKAN_INTERNAL_DescriptorSetLayoutHashFunction(void *userdata, const void *key)
- {
- DescriptorSetLayoutHashTableKey *hashTableKey = (DescriptorSetLayoutHashTableKey *)key;
- /* The algorithm for this hashing function
- * is taken from Josh Bloch's "Effective Java".
- * (https://stackoverflow.com/a/113600/12492383)
- */
- const Uint32 hashFactor = 31;
- Uint32 result = 1;
- result = result * hashFactor + hashTableKey->shaderStage;
- result = result * hashFactor + hashTableKey->samplerCount;
- result = result * hashFactor + hashTableKey->storageTextureCount;
- result = result * hashFactor + hashTableKey->storageBufferCount;
- result = result * hashFactor + hashTableKey->writeStorageTextureCount;
- result = result * hashFactor + hashTableKey->writeStorageBufferCount;
- result = result * hashFactor + hashTableKey->uniformBufferCount;
- return result;
- }
- static bool SDLCALL VULKAN_INTERNAL_DescriptorSetLayoutHashKeyMatch(void *userdata, const void *aKey, const void *bKey)
- {
- return SDL_memcmp(aKey, bKey, sizeof(DescriptorSetLayoutHashTableKey)) == 0;
- }
- static void SDLCALL VULKAN_INTERNAL_DescriptorSetLayoutHashDestroy(void *userdata, const void *key, const void *value)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)userdata;
- DescriptorSetLayout *layout = (DescriptorSetLayout *)value;
- VULKAN_INTERNAL_DestroyDescriptorSetLayout(renderer, layout);
- SDL_free((void *)key);
- }
- static Uint32 SDLCALL VULKAN_INTERNAL_CommandPoolHashFunction(void *userdata, const void *key)
- {
- return (Uint32)((CommandPoolHashTableKey *)key)->threadID;
- }
- static bool SDLCALL VULKAN_INTERNAL_CommandPoolHashKeyMatch(void *userdata, const void *aKey, const void *bKey)
- {
- CommandPoolHashTableKey *a = (CommandPoolHashTableKey *)aKey;
- CommandPoolHashTableKey *b = (CommandPoolHashTableKey *)bKey;
- return a->threadID == b->threadID;
- }
- static void SDLCALL VULKAN_INTERNAL_CommandPoolHashDestroy(void *userdata, const void *key, const void *value)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)userdata;
- VulkanCommandPool *pool = (VulkanCommandPool *)value;
- VULKAN_INTERNAL_DestroyCommandPool(renderer, pool);
- SDL_free((void *)key);
- }
- static Uint32 SDLCALL VULKAN_INTERNAL_RenderPassHashFunction(void *userdata, const void *key)
- {
- RenderPassHashTableKey *hashTableKey = (RenderPassHashTableKey *)key;
- /* The algorithm for this hashing function
- * is taken from Josh Bloch's "Effective Java".
- * (https://stackoverflow.com/a/113600/12492383)
- */
- const Uint32 hashFactor = 31;
- Uint32 result = 1;
- for (Uint32 i = 0; i < hashTableKey->numColorTargets; i += 1) {
- result = result * hashFactor + hashTableKey->colorTargetDescriptions[i].loadOp;
- result = result * hashFactor + hashTableKey->colorTargetDescriptions[i].storeOp;
- result = result * hashFactor + hashTableKey->colorTargetDescriptions[i].format;
- }
- for (Uint32 i = 0; i < hashTableKey->numResolveTargets; i += 1) {
- result = result * hashFactor + hashTableKey->resolveTargetFormats[i];
- }
- result = result * hashFactor + hashTableKey->depthStencilTargetDescription.loadOp;
- result = result * hashFactor + hashTableKey->depthStencilTargetDescription.storeOp;
- result = result * hashFactor + hashTableKey->depthStencilTargetDescription.stencilLoadOp;
- result = result * hashFactor + hashTableKey->depthStencilTargetDescription.stencilStoreOp;
- result = result * hashFactor + hashTableKey->depthStencilTargetDescription.format;
- result = result * hashFactor + hashTableKey->sampleCount;
- return result;
- }
- static bool SDLCALL VULKAN_INTERNAL_RenderPassHashKeyMatch(void *userdata, const void *aKey, const void *bKey)
- {
- RenderPassHashTableKey *a = (RenderPassHashTableKey *)aKey;
- RenderPassHashTableKey *b = (RenderPassHashTableKey *)bKey;
- if (a->numColorTargets != b->numColorTargets) {
- return 0;
- }
- if (a->numResolveTargets != b->numResolveTargets) {
- return 0;
- }
- if (a->sampleCount != b->sampleCount) {
- return 0;
- }
- for (Uint32 i = 0; i < a->numColorTargets; i += 1) {
- if (a->colorTargetDescriptions[i].format != b->colorTargetDescriptions[i].format) {
- return 0;
- }
- if (a->colorTargetDescriptions[i].loadOp != b->colorTargetDescriptions[i].loadOp) {
- return 0;
- }
- if (a->colorTargetDescriptions[i].storeOp != b->colorTargetDescriptions[i].storeOp) {
- return 0;
- }
- }
- for (Uint32 i = 0; i < a->numResolveTargets; i += 1) {
- if (a->resolveTargetFormats[i] != b->resolveTargetFormats[i]) {
- return 0;
- }
- }
- if (a->depthStencilTargetDescription.format != b->depthStencilTargetDescription.format) {
- return 0;
- }
- if (a->depthStencilTargetDescription.loadOp != b->depthStencilTargetDescription.loadOp) {
- return 0;
- }
- if (a->depthStencilTargetDescription.storeOp != b->depthStencilTargetDescription.storeOp) {
- return 0;
- }
- if (a->depthStencilTargetDescription.stencilLoadOp != b->depthStencilTargetDescription.stencilLoadOp) {
- return 0;
- }
- if (a->depthStencilTargetDescription.stencilStoreOp != b->depthStencilTargetDescription.stencilStoreOp) {
- return 0;
- }
- return 1;
- }
- static void SDLCALL VULKAN_INTERNAL_RenderPassHashDestroy(void *userdata, const void *key, const void *value)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)userdata;
- VulkanRenderPassHashTableValue *renderPassWrapper = (VulkanRenderPassHashTableValue *)value;
- renderer->vkDestroyRenderPass(
- renderer->logicalDevice,
- renderPassWrapper->handle,
- NULL);
- SDL_free(renderPassWrapper);
- SDL_free((void *)key);
- }
- static Uint32 SDLCALL VULKAN_INTERNAL_FramebufferHashFunction(void *userdata, const void *key)
- {
- FramebufferHashTableKey *hashTableKey = (FramebufferHashTableKey *)key;
- /* The algorithm for this hashing function
- * is taken from Josh Bloch's "Effective Java".
- * (https://stackoverflow.com/a/113600/12492383)
- */
- const Uint32 hashFactor = 31;
- Uint32 result = 1;
- for (Uint32 i = 0; i < hashTableKey->numColorTargets; i += 1) {
- result = result * hashFactor + (Uint32)(uintptr_t)hashTableKey->colorAttachmentViews[i];
- }
- for (Uint32 i = 0; i < hashTableKey->numResolveAttachments; i += 1) {
- result = result * hashFactor + (Uint32)(uintptr_t)hashTableKey->resolveAttachmentViews[i];
- }
- result = result * hashFactor + (Uint32)(uintptr_t)hashTableKey->depthStencilAttachmentView;
- result = result * hashFactor + hashTableKey->width;
- result = result * hashFactor + hashTableKey->height;
- return result;
- }
- static bool SDLCALL VULKAN_INTERNAL_FramebufferHashKeyMatch(void *userdata, const void *aKey, const void *bKey)
- {
- FramebufferHashTableKey *a = (FramebufferHashTableKey *)aKey;
- FramebufferHashTableKey *b = (FramebufferHashTableKey *)bKey;
- if (a->numColorTargets != b->numColorTargets) {
- return 0;
- }
- if (a->numResolveAttachments != b->numResolveAttachments) {
- return 0;
- }
- for (Uint32 i = 0; i < a->numColorTargets; i += 1) {
- if (a->colorAttachmentViews[i] != b->colorAttachmentViews[i]) {
- return 0;
- }
- }
- for (Uint32 i = 0; i < a->numResolveAttachments; i += 1) {
- if (a->resolveAttachmentViews[i] != b->resolveAttachmentViews[i]) {
- return 0;
- }
- }
- if (a->depthStencilAttachmentView != b->depthStencilAttachmentView) {
- return 0;
- }
- if (a->width != b->width) {
- return 0;
- }
- if (a->height != b->height) {
- return 0;
- }
- return 1;
- }
- static void SDLCALL VULKAN_INTERNAL_FramebufferHashDestroy(void *userdata, const void *key, const void *value)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)userdata;
- VulkanFramebuffer *framebuffer = (VulkanFramebuffer *)value;
- VULKAN_INTERNAL_ReleaseFramebuffer(renderer, framebuffer);
- SDL_free((void *)key);
- }
- // Descriptor pools
- static bool VULKAN_INTERNAL_AllocateDescriptorSets(
- VulkanRenderer *renderer,
- VkDescriptorPool descriptorPool,
- VkDescriptorSetLayout descriptorSetLayout,
- Uint32 descriptorSetCount,
- VkDescriptorSet *descriptorSetArray)
- {
- VkDescriptorSetAllocateInfo descriptorSetAllocateInfo;
- VkDescriptorSetLayout *descriptorSetLayouts = SDL_stack_alloc(VkDescriptorSetLayout, descriptorSetCount);
- VkResult vulkanResult;
- Uint32 i;
- for (i = 0; i < descriptorSetCount; i += 1) {
- descriptorSetLayouts[i] = descriptorSetLayout;
- }
- descriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
- descriptorSetAllocateInfo.pNext = NULL;
- descriptorSetAllocateInfo.descriptorPool = descriptorPool;
- descriptorSetAllocateInfo.descriptorSetCount = descriptorSetCount;
- descriptorSetAllocateInfo.pSetLayouts = descriptorSetLayouts;
- vulkanResult = renderer->vkAllocateDescriptorSets(
- renderer->logicalDevice,
- &descriptorSetAllocateInfo,
- descriptorSetArray);
- SDL_stack_free(descriptorSetLayouts);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkAllocateDescriptorSets, false);
- return true;
- }
- static bool VULKAN_INTERNAL_AllocateDescriptorsFromPool(
- VulkanRenderer *renderer,
- DescriptorSetLayout *descriptorSetLayout,
- DescriptorSetPool *descriptorSetPool)
- {
- VkDescriptorPoolSize descriptorPoolSizes[
- MAX_TEXTURE_SAMPLERS_PER_STAGE +
- MAX_STORAGE_TEXTURES_PER_STAGE +
- MAX_STORAGE_BUFFERS_PER_STAGE +
- MAX_COMPUTE_WRITE_TEXTURES +
- MAX_COMPUTE_WRITE_BUFFERS +
- MAX_UNIFORM_BUFFERS_PER_STAGE];
- VkDescriptorPoolCreateInfo descriptorPoolInfo;
- VkDescriptorPool pool;
- VkResult vulkanResult;
- // Category 1
- for (Uint32 i = 0; i < descriptorSetLayout->samplerCount; i += 1) {
- descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
- descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE;
- }
- for (Uint32 i = descriptorSetLayout->samplerCount; i < descriptorSetLayout->samplerCount + descriptorSetLayout->storageTextureCount; i += 1) {
- descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring the storage image as a sampled image, because shaders are stupid.
- descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE;
- }
- for (Uint32 i = descriptorSetLayout->samplerCount + descriptorSetLayout->storageTextureCount; i < descriptorSetLayout->samplerCount + descriptorSetLayout->storageTextureCount + descriptorSetLayout->storageBufferCount; i += 1) {
- descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE;
- }
- // Category 2
- for (Uint32 i = 0; i < descriptorSetLayout->writeStorageTextureCount; i += 1) {
- descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
- descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE;
- }
- for (Uint32 i = descriptorSetLayout->writeStorageTextureCount; i < descriptorSetLayout->writeStorageTextureCount + descriptorSetLayout->writeStorageBufferCount; i += 1) {
- descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE;
- }
- // Category 3
- for (Uint32 i = 0; i < descriptorSetLayout->uniformBufferCount; i += 1) {
- descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
- descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE;
- }
- descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
- descriptorPoolInfo.pNext = NULL;
- descriptorPoolInfo.flags = 0;
- descriptorPoolInfo.maxSets = DESCRIPTOR_POOL_SIZE;
- descriptorPoolInfo.poolSizeCount =
- descriptorSetLayout->samplerCount +
- descriptorSetLayout->storageTextureCount +
- descriptorSetLayout->storageBufferCount +
- descriptorSetLayout->writeStorageTextureCount +
- descriptorSetLayout->writeStorageBufferCount +
- descriptorSetLayout->uniformBufferCount;
- descriptorPoolInfo.pPoolSizes = descriptorPoolSizes;
- vulkanResult = renderer->vkCreateDescriptorPool(
- renderer->logicalDevice,
- &descriptorPoolInfo,
- NULL,
- &pool);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateDescriptorPool, false);
- descriptorSetPool->poolCount += 1;
- descriptorSetPool->descriptorPools = SDL_realloc(
- descriptorSetPool->descriptorPools,
- sizeof(VkDescriptorPool) * descriptorSetPool->poolCount);
- descriptorSetPool->descriptorPools[descriptorSetPool->poolCount - 1] = pool;
- descriptorSetPool->descriptorSets = SDL_realloc(
- descriptorSetPool->descriptorSets,
- sizeof(VkDescriptorSet) * descriptorSetPool->poolCount * DESCRIPTOR_POOL_SIZE);
- if (!VULKAN_INTERNAL_AllocateDescriptorSets(
- renderer,
- pool,
- descriptorSetLayout->descriptorSetLayout,
- DESCRIPTOR_POOL_SIZE,
- &descriptorSetPool->descriptorSets[descriptorSetPool->descriptorSetCount])) {
- return false;
- }
- descriptorSetPool->descriptorSetCount += DESCRIPTOR_POOL_SIZE;
- return true;
- }
- // NOTE: these categories should be mutually exclusive
- static DescriptorSetLayout *VULKAN_INTERNAL_FetchDescriptorSetLayout(
- VulkanRenderer *renderer,
- VkShaderStageFlagBits shaderStage,
- // Category 1: read resources
- Uint32 samplerCount,
- Uint32 storageTextureCount,
- Uint32 storageBufferCount,
- // Category 2: write resources
- Uint32 writeStorageTextureCount,
- Uint32 writeStorageBufferCount,
- // Category 3: uniform buffers
- Uint32 uniformBufferCount)
- {
- DescriptorSetLayoutHashTableKey key;
- SDL_zero(key);
- DescriptorSetLayout *layout = NULL;
- key.shaderStage = shaderStage;
- key.samplerCount = samplerCount;
- key.storageTextureCount = storageTextureCount;
- key.storageBufferCount = storageBufferCount;
- key.writeStorageTextureCount = writeStorageTextureCount;
- key.writeStorageBufferCount = writeStorageBufferCount;
- key.uniformBufferCount = uniformBufferCount;
- SDL_LockMutex(renderer->descriptorSetLayoutFetchLock);
- if (SDL_FindInHashTable(
- renderer->descriptorSetLayoutHashTable,
- (const void *)&key,
- (const void **)&layout)) {
- SDL_UnlockMutex(renderer->descriptorSetLayoutFetchLock);
- return layout;
- }
- VkDescriptorSetLayout descriptorSetLayout;
- VkDescriptorSetLayoutBinding descriptorSetLayoutBindings[
- MAX_TEXTURE_SAMPLERS_PER_STAGE +
- MAX_STORAGE_TEXTURES_PER_STAGE +
- MAX_STORAGE_BUFFERS_PER_STAGE +
- MAX_COMPUTE_WRITE_TEXTURES +
- MAX_COMPUTE_WRITE_BUFFERS];
- VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo;
- descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
- descriptorSetLayoutCreateInfo.pNext = NULL;
- descriptorSetLayoutCreateInfo.flags = 0;
- // Category 1
- for (Uint32 i = 0; i < samplerCount; i += 1) {
- descriptorSetLayoutBindings[i].binding = i;
- descriptorSetLayoutBindings[i].descriptorCount = 1;
- descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
- descriptorSetLayoutBindings[i].stageFlags = shaderStage;
- descriptorSetLayoutBindings[i].pImmutableSamplers = NULL;
- }
- for (Uint32 i = samplerCount; i < samplerCount + storageTextureCount; i += 1) {
- descriptorSetLayoutBindings[i].binding = i;
- descriptorSetLayoutBindings[i].descriptorCount = 1;
- descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring the storage image as a sampled image, because shaders are stupid.
- descriptorSetLayoutBindings[i].stageFlags = shaderStage;
- descriptorSetLayoutBindings[i].pImmutableSamplers = NULL;
- }
- for (Uint32 i = samplerCount + storageTextureCount; i < samplerCount + storageTextureCount + storageBufferCount; i += 1) {
- descriptorSetLayoutBindings[i].binding = i;
- descriptorSetLayoutBindings[i].descriptorCount = 1;
- descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- descriptorSetLayoutBindings[i].stageFlags = shaderStage;
- descriptorSetLayoutBindings[i].pImmutableSamplers = NULL;
- }
- // Category 2
- for (Uint32 i = 0; i < writeStorageTextureCount; i += 1) {
- descriptorSetLayoutBindings[i].binding = i;
- descriptorSetLayoutBindings[i].descriptorCount = 1;
- descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
- descriptorSetLayoutBindings[i].stageFlags = shaderStage;
- descriptorSetLayoutBindings[i].pImmutableSamplers = NULL;
- }
- for (Uint32 i = writeStorageTextureCount; i < writeStorageTextureCount + writeStorageBufferCount; i += 1) {
- descriptorSetLayoutBindings[i].binding = i;
- descriptorSetLayoutBindings[i].descriptorCount = 1;
- descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- descriptorSetLayoutBindings[i].stageFlags = shaderStage;
- descriptorSetLayoutBindings[i].pImmutableSamplers = NULL;
- }
- // Category 3
- for (Uint32 i = 0; i < uniformBufferCount; i += 1) {
- descriptorSetLayoutBindings[i].binding = i;
- descriptorSetLayoutBindings[i].descriptorCount = 1;
- descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
- descriptorSetLayoutBindings[i].stageFlags = shaderStage;
- descriptorSetLayoutBindings[i].pImmutableSamplers = NULL;
- }
- descriptorSetLayoutCreateInfo.pBindings = descriptorSetLayoutBindings;
- descriptorSetLayoutCreateInfo.bindingCount =
- samplerCount +
- storageTextureCount +
- storageBufferCount +
- writeStorageTextureCount +
- writeStorageBufferCount +
- uniformBufferCount;
- VkResult vulkanResult = renderer->vkCreateDescriptorSetLayout(
- renderer->logicalDevice,
- &descriptorSetLayoutCreateInfo,
- NULL,
- &descriptorSetLayout);
- if (vulkanResult != VK_SUCCESS) {
- SDL_UnlockMutex(renderer->descriptorSetLayoutFetchLock);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateDescriptorSetLayout, NULL);
- }
- layout = SDL_malloc(sizeof(DescriptorSetLayout));
- layout->descriptorSetLayout = descriptorSetLayout;
- layout->samplerCount = samplerCount;
- layout->storageBufferCount = storageBufferCount;
- layout->storageTextureCount = storageTextureCount;
- layout->writeStorageBufferCount = writeStorageBufferCount;
- layout->writeStorageTextureCount = writeStorageTextureCount;
- layout->uniformBufferCount = uniformBufferCount;
- layout->ID = SDL_AtomicIncRef(&renderer->layoutResourceID);
- DescriptorSetLayoutHashTableKey *allocedKey = SDL_malloc(sizeof(DescriptorSetLayoutHashTableKey));
- SDL_memcpy(allocedKey, &key, sizeof(DescriptorSetLayoutHashTableKey));
- SDL_InsertIntoHashTable(
- renderer->descriptorSetLayoutHashTable,
- (const void *)allocedKey,
- (const void *)layout, true);
- SDL_UnlockMutex(renderer->descriptorSetLayoutFetchLock);
- return layout;
- }
- static VulkanGraphicsPipelineResourceLayout *VULKAN_INTERNAL_FetchGraphicsPipelineResourceLayout(
- VulkanRenderer *renderer,
- VulkanShader *vertexShader,
- VulkanShader *fragmentShader)
- {
- GraphicsPipelineResourceLayoutHashTableKey key;
- SDL_zero(key);
- VulkanGraphicsPipelineResourceLayout *pipelineResourceLayout = NULL;
- key.vertexSamplerCount = vertexShader->numSamplers;
- key.vertexStorageTextureCount = vertexShader->numStorageTextures;
- key.vertexStorageBufferCount = vertexShader->numStorageBuffers;
- key.vertexUniformBufferCount = vertexShader->numUniformBuffers;
- key.fragmentSamplerCount = fragmentShader->numSamplers;
- key.fragmentStorageTextureCount = fragmentShader->numStorageTextures;
- key.fragmentStorageBufferCount = fragmentShader->numStorageBuffers;
- key.fragmentUniformBufferCount = fragmentShader->numUniformBuffers;
- SDL_LockMutex(renderer->graphicsPipelineLayoutFetchLock);
- if (SDL_FindInHashTable(
- renderer->graphicsPipelineResourceLayoutHashTable,
- (const void *)&key,
- (const void **)&pipelineResourceLayout)) {
- SDL_UnlockMutex(renderer->graphicsPipelineLayoutFetchLock);
- return pipelineResourceLayout;
- }
- VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo;
- VkDescriptorSetLayout descriptorSetLayouts[4];
- VkResult vulkanResult;
- pipelineResourceLayout = SDL_calloc(1, sizeof(VulkanGraphicsPipelineResourceLayout));
- pipelineResourceLayout->descriptorSetLayouts[0] = VULKAN_INTERNAL_FetchDescriptorSetLayout(
- renderer,
- VK_SHADER_STAGE_VERTEX_BIT,
- vertexShader->numSamplers,
- vertexShader->numStorageTextures,
- vertexShader->numStorageBuffers,
- 0,
- 0,
- 0);
- pipelineResourceLayout->descriptorSetLayouts[1] = VULKAN_INTERNAL_FetchDescriptorSetLayout(
- renderer,
- VK_SHADER_STAGE_VERTEX_BIT,
- 0,
- 0,
- 0,
- 0,
- 0,
- vertexShader->numUniformBuffers);
- pipelineResourceLayout->descriptorSetLayouts[2] = VULKAN_INTERNAL_FetchDescriptorSetLayout(
- renderer,
- VK_SHADER_STAGE_FRAGMENT_BIT,
- fragmentShader->numSamplers,
- fragmentShader->numStorageTextures,
- fragmentShader->numStorageBuffers,
- 0,
- 0,
- 0);
- pipelineResourceLayout->descriptorSetLayouts[3] = VULKAN_INTERNAL_FetchDescriptorSetLayout(
- renderer,
- VK_SHADER_STAGE_FRAGMENT_BIT,
- 0,
- 0,
- 0,
- 0,
- 0,
- fragmentShader->numUniformBuffers);
- descriptorSetLayouts[0] = pipelineResourceLayout->descriptorSetLayouts[0]->descriptorSetLayout;
- descriptorSetLayouts[1] = pipelineResourceLayout->descriptorSetLayouts[1]->descriptorSetLayout;
- descriptorSetLayouts[2] = pipelineResourceLayout->descriptorSetLayouts[2]->descriptorSetLayout;
- descriptorSetLayouts[3] = pipelineResourceLayout->descriptorSetLayouts[3]->descriptorSetLayout;
- pipelineResourceLayout->vertexSamplerCount = vertexShader->numSamplers;
- pipelineResourceLayout->vertexStorageTextureCount = vertexShader->numStorageTextures;
- pipelineResourceLayout->vertexStorageBufferCount = vertexShader->numStorageBuffers;
- pipelineResourceLayout->vertexUniformBufferCount = vertexShader->numUniformBuffers;
- pipelineResourceLayout->fragmentSamplerCount = fragmentShader->numSamplers;
- pipelineResourceLayout->fragmentStorageTextureCount = fragmentShader->numStorageTextures;
- pipelineResourceLayout->fragmentStorageBufferCount = fragmentShader->numStorageBuffers;
- pipelineResourceLayout->fragmentUniformBufferCount = fragmentShader->numUniformBuffers;
- // Create the pipeline layout
- pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
- pipelineLayoutCreateInfo.pNext = NULL;
- pipelineLayoutCreateInfo.flags = 0;
- pipelineLayoutCreateInfo.setLayoutCount = 4;
- pipelineLayoutCreateInfo.pSetLayouts = descriptorSetLayouts;
- pipelineLayoutCreateInfo.pushConstantRangeCount = 0;
- pipelineLayoutCreateInfo.pPushConstantRanges = NULL;
- vulkanResult = renderer->vkCreatePipelineLayout(
- renderer->logicalDevice,
- &pipelineLayoutCreateInfo,
- NULL,
- &pipelineResourceLayout->pipelineLayout);
- if (vulkanResult != VK_SUCCESS) {
- VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout(renderer, pipelineResourceLayout);
- SDL_UnlockMutex(renderer->graphicsPipelineLayoutFetchLock);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreatePipelineLayout, NULL);
- }
- GraphicsPipelineResourceLayoutHashTableKey *allocedKey = SDL_malloc(sizeof(GraphicsPipelineResourceLayoutHashTableKey));
- SDL_memcpy(allocedKey, &key, sizeof(GraphicsPipelineResourceLayoutHashTableKey));
- SDL_InsertIntoHashTable(
- renderer->graphicsPipelineResourceLayoutHashTable,
- (const void *)allocedKey,
- (const void *)pipelineResourceLayout, true);
- SDL_UnlockMutex(renderer->graphicsPipelineLayoutFetchLock);
- return pipelineResourceLayout;
- }
- static VulkanComputePipelineResourceLayout *VULKAN_INTERNAL_FetchComputePipelineResourceLayout(
- VulkanRenderer *renderer,
- const SDL_GPUComputePipelineCreateInfo *createinfo)
- {
- ComputePipelineResourceLayoutHashTableKey key;
- SDL_zero(key);
- VulkanComputePipelineResourceLayout *pipelineResourceLayout = NULL;
- key.samplerCount = createinfo->num_samplers;
- key.readonlyStorageTextureCount = createinfo->num_readonly_storage_textures;
- key.readonlyStorageBufferCount = createinfo->num_readonly_storage_buffers;
- key.readWriteStorageTextureCount = createinfo->num_readwrite_storage_textures;
- key.readWriteStorageBufferCount = createinfo->num_readwrite_storage_buffers;
- key.uniformBufferCount = createinfo->num_uniform_buffers;
- SDL_LockMutex(renderer->computePipelineLayoutFetchLock);
- if (SDL_FindInHashTable(
- renderer->computePipelineResourceLayoutHashTable,
- (const void *)&key,
- (const void **)&pipelineResourceLayout)) {
- SDL_UnlockMutex(renderer->computePipelineLayoutFetchLock);
- return pipelineResourceLayout;
- }
- VkDescriptorSetLayout descriptorSetLayouts[3];
- VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo;
- VkResult vulkanResult;
- pipelineResourceLayout = SDL_calloc(1, sizeof(VulkanComputePipelineResourceLayout));
- pipelineResourceLayout->descriptorSetLayouts[0] = VULKAN_INTERNAL_FetchDescriptorSetLayout(
- renderer,
- VK_SHADER_STAGE_COMPUTE_BIT,
- createinfo->num_samplers,
- createinfo->num_readonly_storage_textures,
- createinfo->num_readonly_storage_buffers,
- 0,
- 0,
- 0);
- pipelineResourceLayout->descriptorSetLayouts[1] = VULKAN_INTERNAL_FetchDescriptorSetLayout(
- renderer,
- VK_SHADER_STAGE_COMPUTE_BIT,
- 0,
- 0,
- 0,
- createinfo->num_readwrite_storage_textures,
- createinfo->num_readwrite_storage_buffers,
- 0);
- pipelineResourceLayout->descriptorSetLayouts[2] = VULKAN_INTERNAL_FetchDescriptorSetLayout(
- renderer,
- VK_SHADER_STAGE_COMPUTE_BIT,
- 0,
- 0,
- 0,
- 0,
- 0,
- createinfo->num_uniform_buffers);
- descriptorSetLayouts[0] = pipelineResourceLayout->descriptorSetLayouts[0]->descriptorSetLayout;
- descriptorSetLayouts[1] = pipelineResourceLayout->descriptorSetLayouts[1]->descriptorSetLayout;
- descriptorSetLayouts[2] = pipelineResourceLayout->descriptorSetLayouts[2]->descriptorSetLayout;
- pipelineResourceLayout->numSamplers = createinfo->num_samplers;
- pipelineResourceLayout->numReadonlyStorageTextures = createinfo->num_readonly_storage_textures;
- pipelineResourceLayout->numReadonlyStorageBuffers = createinfo->num_readonly_storage_buffers;
- pipelineResourceLayout->numReadWriteStorageTextures = createinfo->num_readwrite_storage_textures;
- pipelineResourceLayout->numReadWriteStorageBuffers = createinfo->num_readwrite_storage_buffers;
- pipelineResourceLayout->numUniformBuffers = createinfo->num_uniform_buffers;
- // Create the pipeline layout
- pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
- pipelineLayoutCreateInfo.pNext = NULL;
- pipelineLayoutCreateInfo.flags = 0;
- pipelineLayoutCreateInfo.setLayoutCount = 3;
- pipelineLayoutCreateInfo.pSetLayouts = descriptorSetLayouts;
- pipelineLayoutCreateInfo.pushConstantRangeCount = 0;
- pipelineLayoutCreateInfo.pPushConstantRanges = NULL;
- vulkanResult = renderer->vkCreatePipelineLayout(
- renderer->logicalDevice,
- &pipelineLayoutCreateInfo,
- NULL,
- &pipelineResourceLayout->pipelineLayout);
- if (vulkanResult != VK_SUCCESS) {
- VULKAN_INTERNAL_DestroyComputePipelineResourceLayout(renderer, pipelineResourceLayout);
- SDL_UnlockMutex(renderer->computePipelineLayoutFetchLock);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreatePipelineLayout, NULL);
- }
- ComputePipelineResourceLayoutHashTableKey *allocedKey = SDL_malloc(sizeof(ComputePipelineResourceLayoutHashTableKey));
- SDL_memcpy(allocedKey, &key, sizeof(ComputePipelineResourceLayoutHashTableKey));
- SDL_InsertIntoHashTable(
- renderer->computePipelineResourceLayoutHashTable,
- (const void *)allocedKey,
- (const void *)pipelineResourceLayout, true);
- SDL_UnlockMutex(renderer->computePipelineLayoutFetchLock);
- return pipelineResourceLayout;
- }
- // Data Buffer
- static VulkanBuffer *VULKAN_INTERNAL_CreateBuffer(
- VulkanRenderer *renderer,
- VkDeviceSize size,
- SDL_GPUBufferUsageFlags usageFlags,
- VulkanBufferType type,
- bool dedicated,
- const char *debugName)
- {
- VulkanBuffer *buffer;
- VkResult vulkanResult;
- VkBufferCreateInfo createinfo;
- VkBufferUsageFlags vulkanUsageFlags = 0;
- Uint8 bindResult;
- if (usageFlags & SDL_GPU_BUFFERUSAGE_VERTEX) {
- vulkanUsageFlags |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
- }
- if (usageFlags & SDL_GPU_BUFFERUSAGE_INDEX) {
- vulkanUsageFlags |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
- }
- if (usageFlags & (SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ |
- SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_READ |
- SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE)) {
- vulkanUsageFlags |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
- }
- if (usageFlags & SDL_GPU_BUFFERUSAGE_INDIRECT) {
- vulkanUsageFlags |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
- }
- if (type == VULKAN_BUFFER_TYPE_UNIFORM) {
- vulkanUsageFlags |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
- } else {
- // GPU buffers need transfer bits for defrag, transfer buffers need them for transfers
- vulkanUsageFlags |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
- }
- buffer = SDL_calloc(1, sizeof(VulkanBuffer));
- buffer->size = size;
- buffer->usage = usageFlags;
- buffer->type = type;
- buffer->markedForDestroy = false;
- buffer->transitioned = false;
- createinfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
- createinfo.pNext = NULL;
- createinfo.flags = 0;
- createinfo.size = size;
- createinfo.usage = vulkanUsageFlags;
- createinfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- createinfo.queueFamilyIndexCount = 1;
- createinfo.pQueueFamilyIndices = &renderer->queueFamilyIndex;
- // Set transfer bits so we can defrag
- createinfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
- vulkanResult = renderer->vkCreateBuffer(
- renderer->logicalDevice,
- &createinfo,
- NULL,
- &buffer->buffer);
- if (vulkanResult != VK_SUCCESS) {
- SDL_free(buffer);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateBuffer, NULL);
- }
- bindResult = VULKAN_INTERNAL_BindMemoryForBuffer(
- renderer,
- buffer->buffer,
- buffer->size,
- buffer->type,
- dedicated,
- &buffer->usedRegion);
- if (bindResult != 1) {
- renderer->vkDestroyBuffer(
- renderer->logicalDevice,
- buffer->buffer,
- NULL);
- SDL_free(buffer);
- SET_STRING_ERROR_AND_RETURN("Failed to bind memory for buffer!", NULL);
- }
- buffer->usedRegion->vulkanBuffer = buffer; // lol
- SDL_SetAtomicInt(&buffer->referenceCount, 0);
- if (renderer->debugMode && renderer->supportsDebugUtils && debugName != NULL) {
- VkDebugUtilsObjectNameInfoEXT nameInfo;
- nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
- nameInfo.pNext = NULL;
- nameInfo.pObjectName = debugName;
- nameInfo.objectType = VK_OBJECT_TYPE_BUFFER;
- nameInfo.objectHandle = (uint64_t)buffer->buffer;
- renderer->vkSetDebugUtilsObjectNameEXT(
- renderer->logicalDevice,
- &nameInfo);
- }
- return buffer;
- }
- static VulkanBufferContainer *VULKAN_INTERNAL_CreateBufferContainer(
- VulkanRenderer *renderer,
- VkDeviceSize size,
- SDL_GPUBufferUsageFlags usageFlags,
- VulkanBufferType type,
- bool dedicated,
- const char *debugName)
- {
- VulkanBufferContainer *bufferContainer;
- VulkanBuffer *buffer;
- buffer = VULKAN_INTERNAL_CreateBuffer(
- renderer,
- size,
- usageFlags,
- type,
- dedicated,
- debugName);
- if (buffer == NULL) {
- return NULL;
- }
- bufferContainer = SDL_calloc(1, sizeof(VulkanBufferContainer));
- bufferContainer->activeBuffer = buffer;
- buffer->container = bufferContainer;
- buffer->containerIndex = 0;
- bufferContainer->bufferCapacity = 1;
- bufferContainer->bufferCount = 1;
- bufferContainer->buffers = SDL_calloc(bufferContainer->bufferCapacity, sizeof(VulkanBuffer *));
- bufferContainer->buffers[0] = bufferContainer->activeBuffer;
- bufferContainer->dedicated = dedicated;
- bufferContainer->debugName = NULL;
- if (debugName != NULL) {
- bufferContainer->debugName = SDL_strdup(debugName);
- }
- return bufferContainer;
- }
- // Texture Subresource Utilities
- static Uint32 VULKAN_INTERNAL_GetTextureSubresourceIndex(
- Uint32 mipLevel,
- Uint32 layer,
- Uint32 numLevels)
- {
- return mipLevel + (layer * numLevels);
- }
- static VulkanTextureSubresource *VULKAN_INTERNAL_FetchTextureSubresource(
- VulkanTextureContainer *textureContainer,
- Uint32 layer,
- Uint32 level)
- {
- Uint32 index = VULKAN_INTERNAL_GetTextureSubresourceIndex(
- level,
- layer,
- textureContainer->header.info.num_levels);
- return &textureContainer->activeTexture->subresources[index];
- }
- static bool VULKAN_INTERNAL_CreateRenderTargetView(
- VulkanRenderer *renderer,
- VulkanTexture *texture,
- Uint32 layerOrDepth,
- Uint32 level,
- VkFormat format,
- VkComponentMapping swizzle,
- VkImageView *pView)
- {
- VkResult vulkanResult;
- VkImageViewCreateInfo imageViewCreateInfo;
- // create framebuffer compatible views for RenderTarget
- imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
- imageViewCreateInfo.pNext = NULL;
- imageViewCreateInfo.flags = 0;
- imageViewCreateInfo.image = texture->image;
- imageViewCreateInfo.format = format;
- imageViewCreateInfo.components = swizzle;
- imageViewCreateInfo.subresourceRange.aspectMask = texture->aspectFlags;
- imageViewCreateInfo.subresourceRange.baseMipLevel = level;
- imageViewCreateInfo.subresourceRange.levelCount = 1;
- imageViewCreateInfo.subresourceRange.baseArrayLayer = layerOrDepth;
- imageViewCreateInfo.subresourceRange.layerCount = 1;
- imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
- vulkanResult = renderer->vkCreateImageView(
- renderer->logicalDevice,
- &imageViewCreateInfo,
- NULL,
- pView);
- if (vulkanResult != VK_SUCCESS) {
- *pView = (VkImageView)VK_NULL_HANDLE;
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateImageView, false);
- }
- return true;
- }
- static bool VULKAN_INTERNAL_CreateSubresourceView(
- VulkanRenderer *renderer,
- const SDL_GPUTextureCreateInfo *createinfo,
- VulkanTexture *texture,
- Uint32 layer,
- Uint32 level,
- VkComponentMapping swizzle,
- VkImageView *pView)
- {
- VkResult vulkanResult;
- VkImageViewCreateInfo imageViewCreateInfo;
- // create framebuffer compatible views for RenderTarget
- imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
- imageViewCreateInfo.pNext = NULL;
- imageViewCreateInfo.flags = 0;
- imageViewCreateInfo.image = texture->image;
- imageViewCreateInfo.format = SDLToVK_TextureFormat[createinfo->format];
- imageViewCreateInfo.components = swizzle;
- imageViewCreateInfo.subresourceRange.aspectMask = texture->aspectFlags;
- imageViewCreateInfo.subresourceRange.baseMipLevel = level;
- imageViewCreateInfo.subresourceRange.levelCount = 1;
- imageViewCreateInfo.subresourceRange.baseArrayLayer = layer;
- imageViewCreateInfo.subresourceRange.layerCount = 1;
- imageViewCreateInfo.viewType = (createinfo->type == SDL_GPU_TEXTURETYPE_3D) ? VK_IMAGE_VIEW_TYPE_3D : VK_IMAGE_VIEW_TYPE_2D;
- vulkanResult = renderer->vkCreateImageView(
- renderer->logicalDevice,
- &imageViewCreateInfo,
- NULL,
- pView);
- if (vulkanResult != VK_SUCCESS) {
- *pView = (VkImageView)VK_NULL_HANDLE;
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateImageView, false);
- }
- return true;
- }
- // Swapchain
- static bool VULKAN_INTERNAL_QuerySwapchainSupport(
- VulkanRenderer *renderer,
- VkPhysicalDevice physicalDevice,
- VkSurfaceKHR surface,
- SwapchainSupportDetails *outputDetails)
- {
- VkResult result;
- VkBool32 supportsPresent;
- renderer->vkGetPhysicalDeviceSurfaceSupportKHR(
- physicalDevice,
- renderer->queueFamilyIndex,
- surface,
- &supportsPresent);
- // Initialize these in case anything fails
- outputDetails->formats = NULL;
- outputDetails->formatsLength = 0;
- outputDetails->presentModes = NULL;
- outputDetails->presentModesLength = 0;
- if (!supportsPresent) {
- SET_STRING_ERROR_AND_RETURN("This surface does not support presenting!", false);
- }
- // Run the device surface queries
- result = renderer->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
- physicalDevice,
- surface,
- &outputDetails->capabilities);
- CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfaceCapabilitiesKHR, false);
- if (!(outputDetails->capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)) {
- SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Opaque presentation unsupported! Expect weird transparency bugs!");
- }
- result = renderer->vkGetPhysicalDeviceSurfaceFormatsKHR(
- physicalDevice,
- surface,
- &outputDetails->formatsLength,
- NULL);
- if (result != VK_SUCCESS) {
- // Make sure the driver didn't mess up this value.
- outputDetails->formatsLength = 0;
- CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfaceFormatsKHR, false);
- }
- result = renderer->vkGetPhysicalDeviceSurfacePresentModesKHR(
- physicalDevice,
- surface,
- &outputDetails->presentModesLength,
- NULL);
- if (result != VK_SUCCESS) {
- // Make sure the driver didn't mess up this value.
- outputDetails->presentModesLength = 0;
- // Reset this one, too.
- outputDetails->formatsLength = 0;
- CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfacePresentModesKHR, false);
- }
- // Generate the arrays, if applicable
- if (outputDetails->formatsLength != 0) {
- outputDetails->formats = (VkSurfaceFormatKHR *)SDL_malloc(
- sizeof(VkSurfaceFormatKHR) * outputDetails->formatsLength);
- if (!outputDetails->formats) { // OOM
- outputDetails->formatsLength = 0;
- outputDetails->presentModesLength = 0;
- return false;
- }
- result = renderer->vkGetPhysicalDeviceSurfaceFormatsKHR(
- physicalDevice,
- surface,
- &outputDetails->formatsLength,
- outputDetails->formats);
- if (result != VK_SUCCESS) {
- SDL_free(outputDetails->formats);
- outputDetails->formats = NULL;
- outputDetails->formatsLength = 0;
- outputDetails->presentModesLength = 0;
- CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfaceFormatsKHR, false);
- }
- }
- if (outputDetails->presentModesLength != 0) {
- outputDetails->presentModes = (VkPresentModeKHR *)SDL_malloc(
- sizeof(VkPresentModeKHR) * outputDetails->presentModesLength);
- if (!outputDetails->presentModes) { // OOM
- SDL_free(outputDetails->formats);
- outputDetails->formats = NULL;
- outputDetails->formatsLength = 0;
- outputDetails->presentModesLength = 0;
- return false;
- }
- result = renderer->vkGetPhysicalDeviceSurfacePresentModesKHR(
- physicalDevice,
- surface,
- &outputDetails->presentModesLength,
- outputDetails->presentModes);
- if (result != VK_SUCCESS) {
- SDL_free(outputDetails->formats);
- SDL_free(outputDetails->presentModes);
- outputDetails->formats = NULL;
- outputDetails->presentModes = NULL;
- outputDetails->formatsLength = 0;
- outputDetails->presentModesLength = 0;
- CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfacePresentModesKHR, false);
- }
- }
- /* If we made it here, all the queries were successful. This does NOT
- * necessarily mean there are any supported formats or present modes!
- */
- return true;
- }
- static bool VULKAN_INTERNAL_VerifySwapSurfaceFormat(
- VkFormat desiredFormat,
- VkColorSpaceKHR desiredColorSpace,
- VkSurfaceFormatKHR *availableFormats,
- Uint32 availableFormatsLength)
- {
- Uint32 i;
- for (i = 0; i < availableFormatsLength; i += 1) {
- if (availableFormats[i].format == desiredFormat &&
- availableFormats[i].colorSpace == desiredColorSpace) {
- return true;
- }
- }
- return false;
- }
- static bool VULKAN_INTERNAL_VerifySwapPresentMode(
- VkPresentModeKHR presentMode,
- const VkPresentModeKHR *availablePresentModes,
- Uint32 availablePresentModesLength)
- {
- Uint32 i;
- for (i = 0; i < availablePresentModesLength; i += 1) {
- if (availablePresentModes[i] == presentMode) {
- return true;
- }
- }
- return false;
- }
- /* It would be nice if VULKAN_INTERNAL_CreateSwapchain could return a bool.
- * Unfortunately, some Win32 NVIDIA drivers are stupid
- * and will return surface extents of (0, 0)
- * in certain edge cases, and the swapchain extents are not allowed to be 0.
- * In this case, the client probably still wants to claim the window
- * or recreate the swapchain, so we should return 2 to indicate retry.
- * -cosmonaut
- */
- #define VULKAN_INTERNAL_TRY_AGAIN 2
- static Uint32 VULKAN_INTERNAL_CreateSwapchain(
- VulkanRenderer *renderer,
- WindowData *windowData)
- {
- VkResult vulkanResult;
- VkSwapchainCreateInfoKHR swapchainCreateInfo;
- VkImage *swapchainImages;
- VkSemaphoreCreateInfo semaphoreCreateInfo;
- SwapchainSupportDetails swapchainSupportDetails;
- bool hasValidSwapchainComposition, hasValidPresentMode;
- VkCompositeAlphaFlagsKHR compositeAlphaFlag = 0;
- Uint32 i;
- windowData->frameCounter = 0;
- if (!VULKAN_INTERNAL_QuerySwapchainSupport(
- renderer,
- renderer->physicalDevice,
- windowData->surface,
- &swapchainSupportDetails)) {
- return false;
- }
- // Verify that we can use the requested composition and present mode
- windowData->format = SwapchainCompositionToFormat[windowData->swapchainComposition];
- windowData->colorSpace = SwapchainCompositionToColorSpace[windowData->swapchainComposition];
- windowData->swapchainSwizzle = SwapchainCompositionSwizzle[windowData->swapchainComposition];
- windowData->usingFallbackFormat = false;
- hasValidSwapchainComposition = VULKAN_INTERNAL_VerifySwapSurfaceFormat(
- windowData->format,
- windowData->colorSpace,
- swapchainSupportDetails.formats,
- swapchainSupportDetails.formatsLength);
- if (!hasValidSwapchainComposition) {
- // Let's try again with the fallback format...
- windowData->format = SwapchainCompositionToFallbackFormat[windowData->swapchainComposition];
- windowData->usingFallbackFormat = true;
- hasValidSwapchainComposition = VULKAN_INTERNAL_VerifySwapSurfaceFormat(
- windowData->format,
- windowData->colorSpace,
- swapchainSupportDetails.formats,
- swapchainSupportDetails.formatsLength);
- }
- hasValidPresentMode = VULKAN_INTERNAL_VerifySwapPresentMode(
- SDLToVK_PresentMode[windowData->presentMode],
- swapchainSupportDetails.presentModes,
- swapchainSupportDetails.presentModesLength);
- if (!hasValidSwapchainComposition || !hasValidPresentMode) {
- if (swapchainSupportDetails.formatsLength > 0) {
- SDL_free(swapchainSupportDetails.formats);
- }
- if (swapchainSupportDetails.presentModesLength > 0) {
- SDL_free(swapchainSupportDetails.presentModes);
- }
- if (!hasValidSwapchainComposition) {
- SET_STRING_ERROR_AND_RETURN("Device does not support requested swapchain composition!", false);
- }
- if (!hasValidPresentMode) {
- SET_STRING_ERROR_AND_RETURN("Device does not support requested present_mode!", false);
- }
- return false;
- }
- // NVIDIA + Win32 can return 0 extent when the window is minimized. Try again!
- if (swapchainSupportDetails.capabilities.currentExtent.width == 0 ||
- swapchainSupportDetails.capabilities.currentExtent.height == 0) {
- if (swapchainSupportDetails.formatsLength > 0) {
- SDL_free(swapchainSupportDetails.formats);
- }
- if (swapchainSupportDetails.presentModesLength > 0) {
- SDL_free(swapchainSupportDetails.presentModes);
- }
- return VULKAN_INTERNAL_TRY_AGAIN;
- }
- Uint32 requestedImageCount = renderer->allowedFramesInFlight;
- #ifdef SDL_PLATFORM_APPLE
- windowData->width = swapchainSupportDetails.capabilities.currentExtent.width;
- windowData->height = swapchainSupportDetails.capabilities.currentExtent.height;
- #else
- windowData->width = SDL_clamp(
- windowData->swapchainCreateWidth,
- swapchainSupportDetails.capabilities.minImageExtent.width,
- swapchainSupportDetails.capabilities.maxImageExtent.width);
- windowData->height = SDL_clamp(windowData->swapchainCreateHeight,
- swapchainSupportDetails.capabilities.minImageExtent.height,
- swapchainSupportDetails.capabilities.maxImageExtent.height);
- #endif
- if (swapchainSupportDetails.capabilities.maxImageCount > 0 &&
- requestedImageCount > swapchainSupportDetails.capabilities.maxImageCount) {
- requestedImageCount = swapchainSupportDetails.capabilities.maxImageCount;
- }
- if (requestedImageCount < swapchainSupportDetails.capabilities.minImageCount) {
- requestedImageCount = swapchainSupportDetails.capabilities.minImageCount;
- }
- if (windowData->presentMode == SDL_GPU_PRESENTMODE_MAILBOX) {
- /* Required for proper triple-buffering.
- * Note that this is below the above maxImageCount check!
- * If the driver advertises MAILBOX but does not support 3 swap
- * images, it's not real mailbox support, so let it fail hard.
- * -flibit
- */
- requestedImageCount = SDL_max(requestedImageCount, 3);
- }
- // Default to opaque, if available, followed by inherit, and overwrite with a value that supports transparency, if necessary.
- if (swapchainSupportDetails.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) {
- compositeAlphaFlag = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
- } else if (swapchainSupportDetails.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) {
- compositeAlphaFlag = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
- }
- if ((windowData->window->flags & SDL_WINDOW_TRANSPARENT) || !compositeAlphaFlag) {
- if (swapchainSupportDetails.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) {
- compositeAlphaFlag = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
- } else if (swapchainSupportDetails.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) {
- compositeAlphaFlag = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
- } else if (swapchainSupportDetails.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) {
- compositeAlphaFlag = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
- } else {
- SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "SDL_WINDOW_TRANSPARENT flag set, but no suitable swapchain composite alpha value supported!");
- }
- }
- swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
- swapchainCreateInfo.pNext = NULL;
- swapchainCreateInfo.flags = 0;
- swapchainCreateInfo.surface = windowData->surface;
- swapchainCreateInfo.minImageCount = requestedImageCount;
- swapchainCreateInfo.imageFormat = windowData->format;
- swapchainCreateInfo.imageColorSpace = windowData->colorSpace;
- swapchainCreateInfo.imageExtent.width = windowData->width;
- swapchainCreateInfo.imageExtent.height = windowData->height;
- swapchainCreateInfo.imageArrayLayers = 1;
- swapchainCreateInfo.imageUsage =
- VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
- VK_IMAGE_USAGE_TRANSFER_DST_BIT;
- swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
- swapchainCreateInfo.queueFamilyIndexCount = 0;
- swapchainCreateInfo.pQueueFamilyIndices = NULL;
- #ifdef SDL_PLATFORM_ANDROID
- swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
- #else
- swapchainCreateInfo.preTransform = swapchainSupportDetails.capabilities.currentTransform;
- #endif
- swapchainCreateInfo.compositeAlpha = compositeAlphaFlag;
- swapchainCreateInfo.presentMode = SDLToVK_PresentMode[windowData->presentMode];
- swapchainCreateInfo.clipped = VK_TRUE;
- // The old swapchain could belong to a surface that no longer exists due to app switching.
- swapchainCreateInfo.oldSwapchain = windowData->needsSurfaceRecreate ? (VkSwapchainKHR)0 : windowData->swapchain;
- vulkanResult = renderer->vkCreateSwapchainKHR(
- renderer->logicalDevice,
- &swapchainCreateInfo,
- NULL,
- &windowData->swapchain);
- if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) {
- renderer->vkDestroySwapchainKHR(renderer->logicalDevice, swapchainCreateInfo.oldSwapchain, NULL);
- }
- if (swapchainSupportDetails.formatsLength > 0) {
- SDL_free(swapchainSupportDetails.formats);
- }
- if (swapchainSupportDetails.presentModesLength > 0) {
- SDL_free(swapchainSupportDetails.presentModes);
- }
- if (vulkanResult != VK_SUCCESS) {
- windowData->swapchain = VK_NULL_HANDLE;
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSwapchainKHR, false);
- }
- vulkanResult = renderer->vkGetSwapchainImagesKHR(
- renderer->logicalDevice,
- windowData->swapchain,
- &windowData->imageCount,
- NULL);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkGetSwapchainImagesKHR, false);
- windowData->textureContainers = SDL_malloc(
- sizeof(VulkanTextureContainer) * windowData->imageCount);
- if (!windowData->textureContainers) { // OOM
- renderer->vkDestroySwapchainKHR(
- renderer->logicalDevice,
- windowData->swapchain,
- NULL);
- windowData->swapchain = VK_NULL_HANDLE;
- return false;
- }
- swapchainImages = SDL_stack_alloc(VkImage, windowData->imageCount);
- vulkanResult = renderer->vkGetSwapchainImagesKHR(
- renderer->logicalDevice,
- windowData->swapchain,
- &windowData->imageCount,
- swapchainImages);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkGetSwapchainImagesKHR, false);
- for (i = 0; i < windowData->imageCount; i += 1) {
- // Initialize dummy container
- SDL_zero(windowData->textureContainers[i]);
- windowData->textureContainers[i].canBeCycled = false;
- windowData->textureContainers[i].header.info.width = windowData->width;
- windowData->textureContainers[i].header.info.height = windowData->height;
- windowData->textureContainers[i].header.info.layer_count_or_depth = 1;
- windowData->textureContainers[i].header.info.format = SwapchainCompositionToSDLFormat(
- windowData->swapchainComposition,
- windowData->usingFallbackFormat);
- windowData->textureContainers[i].header.info.type = SDL_GPU_TEXTURETYPE_2D;
- windowData->textureContainers[i].header.info.num_levels = 1;
- windowData->textureContainers[i].header.info.sample_count = SDL_GPU_SAMPLECOUNT_1;
- windowData->textureContainers[i].header.info.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
- windowData->textureContainers[i].activeTexture = SDL_malloc(sizeof(VulkanTexture));
- windowData->textureContainers[i].activeTexture->image = swapchainImages[i];
- // Swapchain memory is managed by the driver
- windowData->textureContainers[i].activeTexture->usedRegion = NULL;
- windowData->textureContainers[i].activeTexture->swizzle = windowData->swapchainSwizzle;
- windowData->textureContainers[i].activeTexture->aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
- windowData->textureContainers[i].activeTexture->depth = 1;
- windowData->textureContainers[i].activeTexture->usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
- windowData->textureContainers[i].activeTexture->container = &windowData->textureContainers[i];
- SDL_SetAtomicInt(&windowData->textureContainers[i].activeTexture->referenceCount, 0);
- // Create slice
- windowData->textureContainers[i].activeTexture->subresourceCount = 1;
- windowData->textureContainers[i].activeTexture->subresources = SDL_malloc(sizeof(VulkanTextureSubresource));
- windowData->textureContainers[i].activeTexture->subresources[0].parent = windowData->textureContainers[i].activeTexture;
- windowData->textureContainers[i].activeTexture->subresources[0].layer = 0;
- windowData->textureContainers[i].activeTexture->subresources[0].level = 0;
- windowData->textureContainers[i].activeTexture->subresources[0].renderTargetViews = SDL_malloc(sizeof(VkImageView));
- if (!VULKAN_INTERNAL_CreateRenderTargetView(
- renderer,
- windowData->textureContainers[i].activeTexture,
- 0,
- 0,
- windowData->format,
- windowData->swapchainSwizzle,
- &windowData->textureContainers[i].activeTexture->subresources[0].renderTargetViews[0])) {
- renderer->vkDestroySwapchainKHR(
- renderer->logicalDevice,
- windowData->swapchain,
- NULL);
- windowData->swapchain = VK_NULL_HANDLE;
- return false;
- }
- }
- SDL_stack_free(swapchainImages);
- semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- semaphoreCreateInfo.pNext = NULL;
- semaphoreCreateInfo.flags = 0;
- for (i = 0; i < MAX_FRAMES_IN_FLIGHT; i += 1) {
- vulkanResult = renderer->vkCreateSemaphore(
- renderer->logicalDevice,
- &semaphoreCreateInfo,
- NULL,
- &windowData->imageAvailableSemaphore[i]);
- if (vulkanResult != VK_SUCCESS) {
- renderer->vkDestroySwapchainKHR(
- renderer->logicalDevice,
- windowData->swapchain,
- NULL);
- windowData->swapchain = VK_NULL_HANDLE;
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSemaphore, false);
- }
- windowData->inFlightFences[i] = NULL;
- }
- windowData->renderFinishedSemaphore = SDL_malloc(
- sizeof(VkSemaphore) * windowData->imageCount);
- for (i = 0; i < windowData->imageCount; i += 1) {
- vulkanResult = renderer->vkCreateSemaphore(
- renderer->logicalDevice,
- &semaphoreCreateInfo,
- NULL,
- &windowData->renderFinishedSemaphore[i]);
- if (vulkanResult != VK_SUCCESS) {
- renderer->vkDestroySwapchainKHR(
- renderer->logicalDevice,
- windowData->swapchain,
- NULL);
- windowData->swapchain = VK_NULL_HANDLE;
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSemaphore, false);
- }
- }
- windowData->needsSwapchainRecreate = false;
- return true;
- }
- // Command Buffers
- static bool VULKAN_INTERNAL_BeginCommandBuffer(
- VulkanRenderer *renderer,
- VulkanCommandBuffer *commandBuffer)
- {
- VkCommandBufferBeginInfo beginInfo;
- VkResult result;
- beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- beginInfo.pNext = NULL;
- beginInfo.flags = 0;
- beginInfo.pInheritanceInfo = NULL;
- beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
- result = renderer->vkBeginCommandBuffer(
- commandBuffer->commandBuffer,
- &beginInfo);
- CHECK_VULKAN_ERROR_AND_RETURN(result, vkBeginCommandBuffer, false);
- return true;
- }
- static bool VULKAN_INTERNAL_EndCommandBuffer(
- VulkanRenderer *renderer,
- VulkanCommandBuffer *commandBuffer)
- {
- VkResult result = renderer->vkEndCommandBuffer(
- commandBuffer->commandBuffer);
- CHECK_VULKAN_ERROR_AND_RETURN(result, vkEndCommandBuffer, false);
- return true;
- }
- static void VULKAN_DestroyDevice(
- SDL_GPUDevice *device)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)device->driverData;
- VulkanMemorySubAllocator *allocator;
- VULKAN_Wait(device->driverData);
- for (Sint32 i = renderer->claimedWindowCount - 1; i >= 0; i -= 1) {
- VULKAN_ReleaseWindow(device->driverData, renderer->claimedWindows[i]->window);
- }
- SDL_free(renderer->claimedWindows);
- VULKAN_Wait(device->driverData);
- SDL_free(renderer->submittedCommandBuffers);
- for (Uint32 i = 0; i < renderer->uniformBufferPoolCount; i += 1) {
- VULKAN_INTERNAL_DestroyBuffer(
- renderer,
- renderer->uniformBufferPool[i]->buffer);
- SDL_free(renderer->uniformBufferPool[i]);
- }
- SDL_free(renderer->uniformBufferPool);
- for (Uint32 i = 0; i < renderer->descriptorSetCachePoolCount; i += 1) {
- VULKAN_INTERNAL_DestroyDescriptorSetCache(
- renderer,
- renderer->descriptorSetCachePool[i]);
- }
- SDL_free(renderer->descriptorSetCachePool);
- for (Uint32 i = 0; i < renderer->fencePool.availableFenceCount; i += 1) {
- renderer->vkDestroyFence(
- renderer->logicalDevice,
- renderer->fencePool.availableFences[i]->fence,
- NULL);
- SDL_free(renderer->fencePool.availableFences[i]);
- }
- SDL_free(renderer->fencePool.availableFences);
- SDL_DestroyMutex(renderer->fencePool.lock);
- SDL_DestroyHashTable(renderer->commandPoolHashTable);
- SDL_DestroyHashTable(renderer->renderPassHashTable);
- SDL_DestroyHashTable(renderer->framebufferHashTable);
- SDL_DestroyHashTable(renderer->graphicsPipelineResourceLayoutHashTable);
- SDL_DestroyHashTable(renderer->computePipelineResourceLayoutHashTable);
- SDL_DestroyHashTable(renderer->descriptorSetLayoutHashTable);
- for (Uint32 i = 0; i < VK_MAX_MEMORY_TYPES; i += 1) {
- allocator = &renderer->memoryAllocator->subAllocators[i];
- for (Sint32 j = allocator->allocationCount - 1; j >= 0; j -= 1) {
- for (Sint32 k = allocator->allocations[j]->usedRegionCount - 1; k >= 0; k -= 1) {
- VULKAN_INTERNAL_RemoveMemoryUsedRegion(
- renderer,
- allocator->allocations[j]->usedRegions[k]);
- }
- VULKAN_INTERNAL_DeallocateMemory(
- renderer,
- allocator,
- j);
- }
- SDL_free(renderer->memoryAllocator->subAllocators[i].allocations);
- SDL_free(renderer->memoryAllocator->subAllocators[i].sortedFreeRegions);
- }
- SDL_free(renderer->memoryAllocator);
- SDL_free(renderer->texturesToDestroy);
- SDL_free(renderer->buffersToDestroy);
- SDL_free(renderer->graphicsPipelinesToDestroy);
- SDL_free(renderer->computePipelinesToDestroy);
- SDL_free(renderer->shadersToDestroy);
- SDL_free(renderer->samplersToDestroy);
- SDL_free(renderer->framebuffersToDestroy);
- SDL_free(renderer->allocationsToDefrag);
- SDL_DestroyMutex(renderer->allocatorLock);
- SDL_DestroyMutex(renderer->disposeLock);
- SDL_DestroyMutex(renderer->submitLock);
- SDL_DestroyMutex(renderer->acquireCommandBufferLock);
- SDL_DestroyMutex(renderer->acquireUniformBufferLock);
- SDL_DestroyMutex(renderer->renderPassFetchLock);
- SDL_DestroyMutex(renderer->framebufferFetchLock);
- SDL_DestroyMutex(renderer->graphicsPipelineLayoutFetchLock);
- SDL_DestroyMutex(renderer->computePipelineLayoutFetchLock);
- SDL_DestroyMutex(renderer->descriptorSetLayoutFetchLock);
- SDL_DestroyMutex(renderer->windowLock);
- renderer->vkDestroyDevice(renderer->logicalDevice, NULL);
- renderer->vkDestroyInstance(renderer->instance, NULL);
- SDL_DestroyProperties(renderer->props);
- SDL_free(renderer);
- SDL_free(device);
- SDL_Vulkan_UnloadLibrary();
- }
- static SDL_PropertiesID VULKAN_GetDeviceProperties(
- SDL_GPUDevice *device)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)device->driverData;
- return renderer->props;
- }
- static DescriptorSetCache *VULKAN_INTERNAL_AcquireDescriptorSetCache(
- VulkanRenderer *renderer)
- {
- DescriptorSetCache *cache;
- if (renderer->descriptorSetCachePoolCount == 0) {
- cache = SDL_malloc(sizeof(DescriptorSetCache));
- cache->poolCount = 0;
- cache->pools = NULL;
- } else {
- cache = renderer->descriptorSetCachePool[renderer->descriptorSetCachePoolCount - 1];
- renderer->descriptorSetCachePoolCount -= 1;
- }
- return cache;
- }
- static void VULKAN_INTERNAL_ReturnDescriptorSetCacheToPool(
- VulkanRenderer *renderer,
- DescriptorSetCache *descriptorSetCache)
- {
- EXPAND_ARRAY_IF_NEEDED(
- renderer->descriptorSetCachePool,
- DescriptorSetCache *,
- renderer->descriptorSetCachePoolCount + 1,
- renderer->descriptorSetCachePoolCapacity,
- renderer->descriptorSetCachePoolCapacity * 2);
- renderer->descriptorSetCachePool[renderer->descriptorSetCachePoolCount] = descriptorSetCache;
- renderer->descriptorSetCachePoolCount += 1;
- for (Uint32 i = 0; i < descriptorSetCache->poolCount; i += 1) {
- descriptorSetCache->pools[i].descriptorSetIndex = 0;
- }
- }
- static VkDescriptorSet VULKAN_INTERNAL_FetchDescriptorSet(
- VulkanRenderer *renderer,
- VulkanCommandBuffer *vulkanCommandBuffer,
- DescriptorSetLayout *descriptorSetLayout)
- {
- // Grow the pool to meet the descriptor set layout ID
- if (descriptorSetLayout->ID >= vulkanCommandBuffer->descriptorSetCache->poolCount) {
- vulkanCommandBuffer->descriptorSetCache->pools = SDL_realloc(
- vulkanCommandBuffer->descriptorSetCache->pools,
- sizeof(DescriptorSetPool) * (descriptorSetLayout->ID + 1));
- for (Uint32 i = vulkanCommandBuffer->descriptorSetCache->poolCount; i < descriptorSetLayout->ID + 1; i += 1) {
- SDL_zero(vulkanCommandBuffer->descriptorSetCache->pools[i]);
- }
- vulkanCommandBuffer->descriptorSetCache->poolCount = descriptorSetLayout->ID + 1;
- }
- DescriptorSetPool *pool =
- &vulkanCommandBuffer->descriptorSetCache->pools[descriptorSetLayout->ID];
- if (pool->descriptorSetIndex == pool->descriptorSetCount) {
- if (!VULKAN_INTERNAL_AllocateDescriptorsFromPool(
- renderer,
- descriptorSetLayout,
- pool)) {
- return VK_NULL_HANDLE;
- }
- }
- VkDescriptorSet descriptorSet = pool->descriptorSets[pool->descriptorSetIndex];
- pool->descriptorSetIndex += 1;
- return descriptorSet;
- }
- static void VULKAN_INTERNAL_BindGraphicsDescriptorSets(
- VulkanRenderer *renderer,
- VulkanCommandBuffer *commandBuffer)
- {
- VulkanGraphicsPipelineResourceLayout *resourceLayout;
- DescriptorSetLayout *descriptorSetLayout;
- VkWriteDescriptorSet writeDescriptorSets[
- (MAX_TEXTURE_SAMPLERS_PER_STAGE +
- MAX_STORAGE_TEXTURES_PER_STAGE +
- MAX_STORAGE_BUFFERS_PER_STAGE +
- MAX_UNIFORM_BUFFERS_PER_STAGE) * 2];
- VkDescriptorBufferInfo bufferInfos[MAX_STORAGE_BUFFERS_PER_STAGE * 2];
- VkDescriptorImageInfo imageInfos[(MAX_TEXTURE_SAMPLERS_PER_STAGE + MAX_STORAGE_TEXTURES_PER_STAGE) * 2];
- Uint32 dynamicOffsets[MAX_UNIFORM_BUFFERS_PER_STAGE * 2];
- Uint32 writeCount = 0;
- Uint32 bufferInfoCount = 0;
- Uint32 imageInfoCount = 0;
- Uint32 dynamicOffsetCount = 0;
- if (
- !commandBuffer->needVertexBufferBind &&
- !commandBuffer->needNewVertexResourceDescriptorSet &&
- !commandBuffer->needNewVertexUniformDescriptorSet &&
- !commandBuffer->needNewVertexUniformOffsets &&
- !commandBuffer->needNewFragmentResourceDescriptorSet &&
- !commandBuffer->needNewFragmentUniformDescriptorSet &&
- !commandBuffer->needNewFragmentUniformOffsets
- ) {
- return;
- }
- if (commandBuffer->needVertexBufferBind && commandBuffer->vertexBufferCount > 0) {
- renderer->vkCmdBindVertexBuffers(
- commandBuffer->commandBuffer,
- 0,
- commandBuffer->vertexBufferCount,
- commandBuffer->vertexBuffers,
- commandBuffer->vertexBufferOffsets);
- commandBuffer->needVertexBufferBind = false;
- }
- resourceLayout = commandBuffer->currentGraphicsPipeline->resourceLayout;
- if (commandBuffer->needNewVertexResourceDescriptorSet) {
- descriptorSetLayout = resourceLayout->descriptorSetLayouts[0];
- commandBuffer->vertexResourceDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet(
- renderer,
- commandBuffer,
- descriptorSetLayout);
- for (Uint32 i = 0; i < resourceLayout->vertexSamplerCount; i += 1) {
- VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount];
- currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- currentWriteDescriptorSet->pNext = NULL;
- currentWriteDescriptorSet->descriptorCount = 1;
- currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
- currentWriteDescriptorSet->dstArrayElement = 0;
- currentWriteDescriptorSet->dstBinding = i;
- currentWriteDescriptorSet->dstSet = commandBuffer->vertexResourceDescriptorSet;
- currentWriteDescriptorSet->pTexelBufferView = NULL;
- currentWriteDescriptorSet->pBufferInfo = NULL;
- imageInfos[imageInfoCount].sampler = commandBuffer->vertexSamplerBindings[i];
- imageInfos[imageInfoCount].imageView = commandBuffer->vertexSamplerTextureViewBindings[i];
- imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount];
- writeCount += 1;
- imageInfoCount += 1;
- }
- for (Uint32 i = 0; i < resourceLayout->vertexStorageTextureCount; i += 1) {
- VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount];
- currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- currentWriteDescriptorSet->pNext = NULL;
- currentWriteDescriptorSet->descriptorCount = 1;
- currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring a storage image as a sampled image, because shaders are stupid.
- currentWriteDescriptorSet->dstArrayElement = 0;
- currentWriteDescriptorSet->dstBinding = resourceLayout->vertexSamplerCount + i;
- currentWriteDescriptorSet->dstSet = commandBuffer->vertexResourceDescriptorSet;
- currentWriteDescriptorSet->pTexelBufferView = NULL;
- currentWriteDescriptorSet->pBufferInfo = NULL;
- imageInfos[imageInfoCount].sampler = VK_NULL_HANDLE;
- imageInfos[imageInfoCount].imageView = commandBuffer->vertexStorageTextureViewBindings[i];
- imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
- currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount];
- writeCount += 1;
- imageInfoCount += 1;
- }
- for (Uint32 i = 0; i < resourceLayout->vertexStorageBufferCount; i += 1) {
- VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount];
- currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- currentWriteDescriptorSet->pNext = NULL;
- currentWriteDescriptorSet->descriptorCount = 1;
- currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- currentWriteDescriptorSet->dstArrayElement = 0;
- currentWriteDescriptorSet->dstBinding = resourceLayout->vertexSamplerCount + resourceLayout->vertexStorageTextureCount + i;
- currentWriteDescriptorSet->dstSet = commandBuffer->vertexResourceDescriptorSet;
- currentWriteDescriptorSet->pTexelBufferView = NULL;
- currentWriteDescriptorSet->pImageInfo = NULL;
- bufferInfos[bufferInfoCount].buffer = commandBuffer->vertexStorageBufferBindings[i];
- bufferInfos[bufferInfoCount].offset = 0;
- bufferInfos[bufferInfoCount].range = VK_WHOLE_SIZE;
- currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount];
- writeCount += 1;
- bufferInfoCount += 1;
- }
- commandBuffer->needNewVertexResourceDescriptorSet = false;
- }
- if (commandBuffer->needNewVertexUniformDescriptorSet) {
- descriptorSetLayout = resourceLayout->descriptorSetLayouts[1];
- commandBuffer->vertexUniformDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet(
- renderer,
- commandBuffer,
- descriptorSetLayout);
- for (Uint32 i = 0; i < resourceLayout->vertexUniformBufferCount; i += 1) {
- VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount];
- currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- currentWriteDescriptorSet->pNext = NULL;
- currentWriteDescriptorSet->descriptorCount = 1;
- currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
- currentWriteDescriptorSet->dstArrayElement = 0;
- currentWriteDescriptorSet->dstBinding = i;
- currentWriteDescriptorSet->dstSet = commandBuffer->vertexUniformDescriptorSet;
- currentWriteDescriptorSet->pTexelBufferView = NULL;
- currentWriteDescriptorSet->pImageInfo = NULL;
- bufferInfos[bufferInfoCount].buffer = commandBuffer->vertexUniformBuffers[i]->buffer->buffer;
- bufferInfos[bufferInfoCount].offset = 0;
- bufferInfos[bufferInfoCount].range = MAX_UBO_SECTION_SIZE;
- currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount];
- writeCount += 1;
- bufferInfoCount += 1;
- }
- commandBuffer->needNewVertexUniformDescriptorSet = false;
- }
- for (Uint32 i = 0; i < resourceLayout->vertexUniformBufferCount; i += 1) {
- dynamicOffsets[dynamicOffsetCount] = commandBuffer->vertexUniformBuffers[i]->drawOffset;
- dynamicOffsetCount += 1;
- }
- if (commandBuffer->needNewFragmentResourceDescriptorSet) {
- descriptorSetLayout = resourceLayout->descriptorSetLayouts[2];
- commandBuffer->fragmentResourceDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet(
- renderer,
- commandBuffer,
- descriptorSetLayout);
- for (Uint32 i = 0; i < resourceLayout->fragmentSamplerCount; i += 1) {
- VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount];
- currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- currentWriteDescriptorSet->pNext = NULL;
- currentWriteDescriptorSet->descriptorCount = 1;
- currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
- currentWriteDescriptorSet->dstArrayElement = 0;
- currentWriteDescriptorSet->dstBinding = i;
- currentWriteDescriptorSet->dstSet = commandBuffer->fragmentResourceDescriptorSet;
- currentWriteDescriptorSet->pTexelBufferView = NULL;
- currentWriteDescriptorSet->pBufferInfo = NULL;
- imageInfos[imageInfoCount].sampler = commandBuffer->fragmentSamplerBindings[i];
- imageInfos[imageInfoCount].imageView = commandBuffer->fragmentSamplerTextureViewBindings[i];
- imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount];
- writeCount += 1;
- imageInfoCount += 1;
- }
- for (Uint32 i = 0; i < resourceLayout->fragmentStorageTextureCount; i += 1) {
- VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount];
- currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- currentWriteDescriptorSet->pNext = NULL;
- currentWriteDescriptorSet->descriptorCount = 1;
- currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring a storage image as a sampled image, because shaders are stupid.
- currentWriteDescriptorSet->dstArrayElement = 0;
- currentWriteDescriptorSet->dstBinding = resourceLayout->fragmentSamplerCount + i;
- currentWriteDescriptorSet->dstSet = commandBuffer->fragmentResourceDescriptorSet;
- currentWriteDescriptorSet->pTexelBufferView = NULL;
- currentWriteDescriptorSet->pBufferInfo = NULL;
- imageInfos[imageInfoCount].sampler = VK_NULL_HANDLE;
- imageInfos[imageInfoCount].imageView = commandBuffer->fragmentStorageTextureViewBindings[i];
- imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
- currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount];
- writeCount += 1;
- imageInfoCount += 1;
- }
- for (Uint32 i = 0; i < resourceLayout->fragmentStorageBufferCount; i += 1) {
- VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount];
- currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- currentWriteDescriptorSet->pNext = NULL;
- currentWriteDescriptorSet->descriptorCount = 1;
- currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- currentWriteDescriptorSet->dstArrayElement = 0;
- currentWriteDescriptorSet->dstBinding = resourceLayout->fragmentSamplerCount + resourceLayout->fragmentStorageTextureCount + i;
- currentWriteDescriptorSet->dstSet = commandBuffer->fragmentResourceDescriptorSet;
- currentWriteDescriptorSet->pTexelBufferView = NULL;
- currentWriteDescriptorSet->pImageInfo = NULL;
- bufferInfos[bufferInfoCount].buffer = commandBuffer->fragmentStorageBufferBindings[i];
- bufferInfos[bufferInfoCount].offset = 0;
- bufferInfos[bufferInfoCount].range = VK_WHOLE_SIZE;
- currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount];
- writeCount += 1;
- bufferInfoCount += 1;
- }
- commandBuffer->needNewFragmentResourceDescriptorSet = false;
- }
- if (commandBuffer->needNewFragmentUniformDescriptorSet) {
- descriptorSetLayout = resourceLayout->descriptorSetLayouts[3];
- commandBuffer->fragmentUniformDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet(
- renderer,
- commandBuffer,
- descriptorSetLayout);
- for (Uint32 i = 0; i < resourceLayout->fragmentUniformBufferCount; i += 1) {
- VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount];
- currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- currentWriteDescriptorSet->pNext = NULL;
- currentWriteDescriptorSet->descriptorCount = 1;
- currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
- currentWriteDescriptorSet->dstArrayElement = 0;
- currentWriteDescriptorSet->dstBinding = i;
- currentWriteDescriptorSet->dstSet = commandBuffer->fragmentUniformDescriptorSet;
- currentWriteDescriptorSet->pTexelBufferView = NULL;
- currentWriteDescriptorSet->pImageInfo = NULL;
- bufferInfos[bufferInfoCount].buffer = commandBuffer->fragmentUniformBuffers[i]->buffer->buffer;
- bufferInfos[bufferInfoCount].offset = 0;
- bufferInfos[bufferInfoCount].range = MAX_UBO_SECTION_SIZE;
- currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount];
- writeCount += 1;
- bufferInfoCount += 1;
- }
- commandBuffer->needNewFragmentUniformDescriptorSet = false;
- }
- for (Uint32 i = 0; i < resourceLayout->fragmentUniformBufferCount; i += 1) {
- dynamicOffsets[dynamicOffsetCount] = commandBuffer->fragmentUniformBuffers[i]->drawOffset;
- dynamicOffsetCount += 1;
- }
- renderer->vkUpdateDescriptorSets(
- renderer->logicalDevice,
- writeCount,
- writeDescriptorSets,
- 0,
- NULL);
- VkDescriptorSet sets[4];
- sets[0] = commandBuffer->vertexResourceDescriptorSet;
- sets[1] = commandBuffer->vertexUniformDescriptorSet;
- sets[2] = commandBuffer->fragmentResourceDescriptorSet;
- sets[3] = commandBuffer->fragmentUniformDescriptorSet;
- renderer->vkCmdBindDescriptorSets(
- commandBuffer->commandBuffer,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- resourceLayout->pipelineLayout,
- 0,
- 4,
- sets,
- dynamicOffsetCount,
- dynamicOffsets);
- commandBuffer->needNewVertexUniformOffsets = false;
- commandBuffer->needNewFragmentUniformOffsets = false;
- }
- static void VULKAN_DrawIndexedPrimitives(
- SDL_GPUCommandBuffer *commandBuffer,
- Uint32 numIndices,
- Uint32 numInstances,
- Uint32 firstIndex,
- Sint32 vertexOffset,
- Uint32 firstInstance)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- VULKAN_INTERNAL_BindGraphicsDescriptorSets(renderer, vulkanCommandBuffer);
- renderer->vkCmdDrawIndexed(
- vulkanCommandBuffer->commandBuffer,
- numIndices,
- numInstances,
- firstIndex,
- vertexOffset,
- firstInstance);
- }
- static void VULKAN_DrawPrimitives(
- SDL_GPUCommandBuffer *commandBuffer,
- Uint32 numVertices,
- Uint32 numInstances,
- Uint32 firstVertex,
- Uint32 firstInstance)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- VULKAN_INTERNAL_BindGraphicsDescriptorSets(renderer, vulkanCommandBuffer);
- renderer->vkCmdDraw(
- vulkanCommandBuffer->commandBuffer,
- numVertices,
- numInstances,
- firstVertex,
- firstInstance);
- }
- static void VULKAN_DrawPrimitivesIndirect(
- SDL_GPUCommandBuffer *commandBuffer,
- SDL_GPUBuffer *buffer,
- Uint32 offset,
- Uint32 drawCount)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)buffer)->activeBuffer;
- Uint32 pitch = sizeof(SDL_GPUIndirectDrawCommand);
- Uint32 i;
- VULKAN_INTERNAL_BindGraphicsDescriptorSets(renderer, vulkanCommandBuffer);
- if (renderer->supportsMultiDrawIndirect) {
- // Real multi-draw!
- renderer->vkCmdDrawIndirect(
- vulkanCommandBuffer->commandBuffer,
- vulkanBuffer->buffer,
- offset,
- drawCount,
- pitch);
- } else {
- // Fake multi-draw...
- for (i = 0; i < drawCount; i += 1) {
- renderer->vkCmdDrawIndirect(
- vulkanCommandBuffer->commandBuffer,
- vulkanBuffer->buffer,
- offset + (pitch * i),
- 1,
- pitch);
- }
- }
- VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, vulkanBuffer);
- }
- static void VULKAN_DrawIndexedPrimitivesIndirect(
- SDL_GPUCommandBuffer *commandBuffer,
- SDL_GPUBuffer *buffer,
- Uint32 offset,
- Uint32 drawCount)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)buffer)->activeBuffer;
- Uint32 pitch = sizeof(SDL_GPUIndexedIndirectDrawCommand);
- Uint32 i;
- VULKAN_INTERNAL_BindGraphicsDescriptorSets(renderer, vulkanCommandBuffer);
- if (renderer->supportsMultiDrawIndirect) {
- // Real multi-draw!
- renderer->vkCmdDrawIndexedIndirect(
- vulkanCommandBuffer->commandBuffer,
- vulkanBuffer->buffer,
- offset,
- drawCount,
- pitch);
- } else {
- // Fake multi-draw...
- for (i = 0; i < drawCount; i += 1) {
- renderer->vkCmdDrawIndexedIndirect(
- vulkanCommandBuffer->commandBuffer,
- vulkanBuffer->buffer,
- offset + (pitch * i),
- 1,
- pitch);
- }
- }
- VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, vulkanBuffer);
- }
- // Debug Naming
- static void VULKAN_INTERNAL_SetBufferName(
- VulkanRenderer *renderer,
- VulkanBuffer *buffer,
- const char *text)
- {
- VkDebugUtilsObjectNameInfoEXT nameInfo;
- if (renderer->debugMode && renderer->supportsDebugUtils) {
- nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
- nameInfo.pNext = NULL;
- nameInfo.pObjectName = text;
- nameInfo.objectType = VK_OBJECT_TYPE_BUFFER;
- nameInfo.objectHandle = (uint64_t)buffer->buffer;
- renderer->vkSetDebugUtilsObjectNameEXT(
- renderer->logicalDevice,
- &nameInfo);
- }
- }
- static void VULKAN_SetBufferName(
- SDL_GPURenderer *driverData,
- SDL_GPUBuffer *buffer,
- const char *text)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- VulkanBufferContainer *container = (VulkanBufferContainer *)buffer;
- size_t textLength = SDL_strlen(text) + 1;
- if (renderer->debugMode && renderer->supportsDebugUtils) {
- container->debugName = SDL_realloc(
- container->debugName,
- textLength);
- SDL_utf8strlcpy(
- container->debugName,
- text,
- textLength);
- for (Uint32 i = 0; i < container->bufferCount; i += 1) {
- VULKAN_INTERNAL_SetBufferName(
- renderer,
- container->buffers[i],
- text);
- }
- }
- }
- static void VULKAN_INTERNAL_SetTextureName(
- VulkanRenderer *renderer,
- VulkanTexture *texture,
- const char *text)
- {
- VkDebugUtilsObjectNameInfoEXT nameInfo;
- if (renderer->debugMode && renderer->supportsDebugUtils) {
- nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
- nameInfo.pNext = NULL;
- nameInfo.pObjectName = text;
- nameInfo.objectType = VK_OBJECT_TYPE_IMAGE;
- nameInfo.objectHandle = (uint64_t)texture->image;
- renderer->vkSetDebugUtilsObjectNameEXT(
- renderer->logicalDevice,
- &nameInfo);
- }
- }
- static void VULKAN_SetTextureName(
- SDL_GPURenderer *driverData,
- SDL_GPUTexture *texture,
- const char *text)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- VulkanTextureContainer *container = (VulkanTextureContainer *)texture;
- size_t textLength = SDL_strlen(text) + 1;
- if (renderer->debugMode && renderer->supportsDebugUtils) {
- container->debugName = SDL_realloc(
- container->debugName,
- textLength);
- SDL_utf8strlcpy(
- container->debugName,
- text,
- textLength);
- for (Uint32 i = 0; i < container->textureCount; i += 1) {
- VULKAN_INTERNAL_SetTextureName(
- renderer,
- container->textures[i],
- text);
- }
- }
- }
- static void VULKAN_InsertDebugLabel(
- SDL_GPUCommandBuffer *commandBuffer,
- const char *text)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- VkDebugUtilsLabelEXT labelInfo;
- if (renderer->supportsDebugUtils) {
- SDL_zero(labelInfo);
- labelInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
- labelInfo.pLabelName = text;
- renderer->vkCmdInsertDebugUtilsLabelEXT(
- vulkanCommandBuffer->commandBuffer,
- &labelInfo);
- }
- }
- static void VULKAN_PushDebugGroup(
- SDL_GPUCommandBuffer *commandBuffer,
- const char *name)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- VkDebugUtilsLabelEXT labelInfo;
- if (renderer->supportsDebugUtils) {
- SDL_zero(labelInfo);
- labelInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
- labelInfo.pLabelName = name;
- renderer->vkCmdBeginDebugUtilsLabelEXT(
- vulkanCommandBuffer->commandBuffer,
- &labelInfo);
- }
- }
- static void VULKAN_PopDebugGroup(
- SDL_GPUCommandBuffer *commandBuffer)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- if (renderer->supportsDebugUtils) {
- renderer->vkCmdEndDebugUtilsLabelEXT(vulkanCommandBuffer->commandBuffer);
- }
- }
- static VulkanTexture *VULKAN_INTERNAL_CreateTexture(
- VulkanRenderer *renderer,
- bool transitionToDefaultLayout,
- const SDL_GPUTextureCreateInfo *createinfo)
- {
- VkResult vulkanResult;
- VkImageCreateInfo imageCreateInfo;
- VkImageCreateFlags imageCreateFlags = 0;
- VkImageViewCreateInfo imageViewCreateInfo;
- Uint8 bindResult;
- VkImageUsageFlags vkUsageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
- Uint32 layerCount = (createinfo->type == SDL_GPU_TEXTURETYPE_3D) ? 1 : createinfo->layer_count_or_depth;
- Uint32 depth = (createinfo->type == SDL_GPU_TEXTURETYPE_3D) ? createinfo->layer_count_or_depth : 1;
- VulkanTexture *texture = SDL_calloc(1, sizeof(VulkanTexture));
- texture->swizzle = SwizzleForSDLFormat(createinfo->format);
- texture->depth = depth;
- texture->usage = createinfo->usage;
- SDL_SetAtomicInt(&texture->referenceCount, 0);
- if (IsDepthFormat(createinfo->format)) {
- texture->aspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT;
- if (IsStencilFormat(createinfo->format)) {
- texture->aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT;
- }
- } else {
- texture->aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
- }
- if (createinfo->type == SDL_GPU_TEXTURETYPE_CUBE || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) {
- imageCreateFlags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
- } else if (createinfo->type == SDL_GPU_TEXTURETYPE_3D) {
- imageCreateFlags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
- }
- if (createinfo->usage & (SDL_GPU_TEXTUREUSAGE_SAMPLER |
- SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ |
- SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ)) {
- vkUsageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT;
- }
- if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) {
- vkUsageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
- }
- if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) {
- vkUsageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
- }
- if (createinfo->usage & (SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE |
- SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE)) {
- vkUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT;
- }
- imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
- imageCreateInfo.pNext = NULL;
- imageCreateInfo.flags = imageCreateFlags;
- imageCreateInfo.imageType = createinfo->type == SDL_GPU_TEXTURETYPE_3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
- imageCreateInfo.format = SDLToVK_TextureFormat[createinfo->format];
- imageCreateInfo.extent.width = createinfo->width;
- imageCreateInfo.extent.height = createinfo->height;
- imageCreateInfo.extent.depth = depth;
- imageCreateInfo.mipLevels = createinfo->num_levels;
- imageCreateInfo.arrayLayers = layerCount;
- imageCreateInfo.samples = SDLToVK_SampleCount[createinfo->sample_count];
- imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
- imageCreateInfo.usage = vkUsageFlags;
- imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- imageCreateInfo.queueFamilyIndexCount = 0;
- imageCreateInfo.pQueueFamilyIndices = NULL;
- imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- vulkanResult = renderer->vkCreateImage(
- renderer->logicalDevice,
- &imageCreateInfo,
- NULL,
- &texture->image);
- if (vulkanResult != VK_SUCCESS) {
- VULKAN_INTERNAL_DestroyTexture(renderer, texture);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateImage, NULL);
- }
- bindResult = VULKAN_INTERNAL_BindMemoryForImage(
- renderer,
- texture->image,
- &texture->usedRegion);
- if (bindResult != 1) {
- renderer->vkDestroyImage(
- renderer->logicalDevice,
- texture->image,
- NULL);
- VULKAN_INTERNAL_DestroyTexture(renderer, texture);
- SET_STRING_ERROR_AND_RETURN("Unable to bind memory for texture!", NULL);
- }
- texture->usedRegion->vulkanTexture = texture; // lol
- if (createinfo->usage & (SDL_GPU_TEXTUREUSAGE_SAMPLER | SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ | SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ)) {
- imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
- imageViewCreateInfo.pNext = NULL;
- imageViewCreateInfo.flags = 0;
- imageViewCreateInfo.image = texture->image;
- imageViewCreateInfo.format = SDLToVK_TextureFormat[createinfo->format];
- imageViewCreateInfo.components = texture->swizzle;
- imageViewCreateInfo.subresourceRange.aspectMask = texture->aspectFlags & ~VK_IMAGE_ASPECT_STENCIL_BIT; // Can't sample stencil values
- imageViewCreateInfo.subresourceRange.baseMipLevel = 0;
- imageViewCreateInfo.subresourceRange.levelCount = createinfo->num_levels;
- imageViewCreateInfo.subresourceRange.baseArrayLayer = 0;
- imageViewCreateInfo.subresourceRange.layerCount = layerCount;
- if (createinfo->type == SDL_GPU_TEXTURETYPE_CUBE) {
- imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
- } else if (createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) {
- imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
- } else if (createinfo->type == SDL_GPU_TEXTURETYPE_3D) {
- imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_3D;
- } else if (createinfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY) {
- imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
- } else {
- imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
- }
- vulkanResult = renderer->vkCreateImageView(
- renderer->logicalDevice,
- &imageViewCreateInfo,
- NULL,
- &texture->fullView);
- if (vulkanResult != VK_SUCCESS) {
- VULKAN_INTERNAL_DestroyTexture(renderer, texture);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, "vkCreateImageView", NULL);
- }
- }
- // Define slices
- texture->subresourceCount = layerCount * createinfo->num_levels;
- texture->subresources = SDL_calloc(
- texture->subresourceCount,
- sizeof(VulkanTextureSubresource));
- for (Uint32 i = 0; i < layerCount; i += 1) {
- for (Uint32 j = 0; j < createinfo->num_levels; j += 1) {
- Uint32 subresourceIndex = VULKAN_INTERNAL_GetTextureSubresourceIndex(
- j,
- i,
- createinfo->num_levels);
- if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) {
- texture->subresources[subresourceIndex].renderTargetViews = SDL_malloc(
- depth * sizeof(VkImageView));
- if (depth > 1) {
- for (Uint32 k = 0; k < depth; k += 1) {
- if (!VULKAN_INTERNAL_CreateRenderTargetView(
- renderer,
- texture,
- k,
- j,
- SDLToVK_TextureFormat[createinfo->format],
- texture->swizzle,
- &texture->subresources[subresourceIndex].renderTargetViews[k])) {
- VULKAN_INTERNAL_DestroyTexture(renderer, texture);
- return NULL;
- }
- }
- } else {
- if (!VULKAN_INTERNAL_CreateRenderTargetView(
- renderer,
- texture,
- i,
- j,
- SDLToVK_TextureFormat[createinfo->format],
- texture->swizzle,
- &texture->subresources[subresourceIndex].renderTargetViews[0])) {
- VULKAN_INTERNAL_DestroyTexture(renderer, texture);
- return NULL;
- }
- }
- }
- if ((createinfo->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) || (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE)) {
- if (!VULKAN_INTERNAL_CreateSubresourceView(
- renderer,
- createinfo,
- texture,
- i,
- j,
- texture->swizzle,
- &texture->subresources[subresourceIndex].computeWriteView)) {
- VULKAN_INTERNAL_DestroyTexture(renderer, texture);
- return NULL;
- }
- }
- if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) {
- if (!VULKAN_INTERNAL_CreateSubresourceView(
- renderer,
- createinfo,
- texture,
- i,
- j,
- texture->swizzle,
- &texture->subresources[subresourceIndex].depthStencilView)) {
- VULKAN_INTERNAL_DestroyTexture(renderer, texture);
- return NULL;
- }
- }
- texture->subresources[subresourceIndex].parent = texture;
- texture->subresources[subresourceIndex].layer = i;
- texture->subresources[subresourceIndex].level = j;
- }
- }
- // Set debug name if applicable
- if (renderer->debugMode && renderer->supportsDebugUtils && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING)) {
- VkDebugUtilsObjectNameInfoEXT nameInfo;
- nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
- nameInfo.pNext = NULL;
- nameInfo.pObjectName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING, NULL);
- nameInfo.objectType = VK_OBJECT_TYPE_IMAGE;
- nameInfo.objectHandle = (uint64_t)texture->image;
- renderer->vkSetDebugUtilsObjectNameEXT(
- renderer->logicalDevice,
- &nameInfo);
- }
- if (transitionToDefaultLayout) {
- // Let's transition to the default barrier state, because for some reason Vulkan doesn't let us do that with initialLayout.
- VulkanCommandBuffer *barrierCommandBuffer = (VulkanCommandBuffer *)VULKAN_AcquireCommandBuffer((SDL_GPURenderer *)renderer);
- VULKAN_INTERNAL_TextureTransitionToDefaultUsage(
- renderer,
- barrierCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED,
- texture);
- VULKAN_INTERNAL_TrackTexture(barrierCommandBuffer, texture);
- if (!VULKAN_Submit((SDL_GPUCommandBuffer *)barrierCommandBuffer)) {
- VULKAN_INTERNAL_DestroyTexture(renderer, texture);
- return NULL;
- }
- }
- return texture;
- }
- static void VULKAN_INTERNAL_CycleActiveBuffer(
- VulkanRenderer *renderer,
- VulkanBufferContainer *container)
- {
- VulkanBuffer *buffer;
- // If a previously-cycled buffer is available, we can use that.
- for (Uint32 i = 0; i < container->bufferCount; i += 1) {
- buffer = container->buffers[i];
- if (SDL_GetAtomicInt(&buffer->referenceCount) == 0) {
- container->activeBuffer = buffer;
- return;
- }
- }
- // No buffer handle is available, create a new one.
- buffer = VULKAN_INTERNAL_CreateBuffer(
- renderer,
- container->activeBuffer->size,
- container->activeBuffer->usage,
- container->activeBuffer->type,
- container->dedicated,
- container->debugName);
- if (!buffer) {
- return;
- }
- EXPAND_ARRAY_IF_NEEDED(
- container->buffers,
- VulkanBuffer *,
- container->bufferCount + 1,
- container->bufferCapacity,
- container->bufferCapacity * 2);
- container->buffers[container->bufferCount] = buffer;
- buffer->container = container;
- buffer->containerIndex = container->bufferCount;
- container->bufferCount += 1;
- container->activeBuffer = buffer;
- }
- static void VULKAN_INTERNAL_CycleActiveTexture(
- VulkanRenderer *renderer,
- VulkanCommandBuffer *commandBuffer,
- VulkanTextureContainer *container)
- {
- VulkanTexture *texture;
- // If a previously-cycled texture is available, we can use that.
- for (Uint32 i = 0; i < container->textureCount; i += 1) {
- texture = container->textures[i];
- if (SDL_GetAtomicInt(&texture->referenceCount) == 0) {
- container->activeTexture = texture;
- return;
- }
- }
- // No texture is available, generate a new one.
- texture = VULKAN_INTERNAL_CreateTexture(
- renderer,
- false,
- &container->header.info);
- VULKAN_INTERNAL_TextureTransitionToDefaultUsage(
- renderer,
- commandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED,
- texture);
- if (!texture) {
- return;
- }
- EXPAND_ARRAY_IF_NEEDED(
- container->textures,
- VulkanTexture *,
- container->textureCount + 1,
- container->textureCapacity,
- container->textureCapacity * 2);
- container->textures[container->textureCount] = texture;
- texture->container = container;
- texture->containerIndex = container->textureCount;
- container->textureCount += 1;
- container->activeTexture = texture;
- }
- static VulkanBuffer *VULKAN_INTERNAL_PrepareBufferForWrite(
- VulkanRenderer *renderer,
- VulkanCommandBuffer *commandBuffer,
- VulkanBufferContainer *bufferContainer,
- bool cycle,
- VulkanBufferUsageMode destinationUsageMode)
- {
- if (
- cycle &&
- SDL_GetAtomicInt(&bufferContainer->activeBuffer->referenceCount) > 0) {
- VULKAN_INTERNAL_CycleActiveBuffer(
- renderer,
- bufferContainer);
- }
- VULKAN_INTERNAL_BufferTransitionFromDefaultUsage(
- renderer,
- commandBuffer,
- destinationUsageMode,
- bufferContainer->activeBuffer);
- return bufferContainer->activeBuffer;
- }
- static VulkanTextureSubresource *VULKAN_INTERNAL_PrepareTextureSubresourceForWrite(
- VulkanRenderer *renderer,
- VulkanCommandBuffer *commandBuffer,
- VulkanTextureContainer *textureContainer,
- Uint32 layer,
- Uint32 level,
- bool cycle,
- VulkanTextureUsageMode destinationUsageMode)
- {
- VulkanTextureSubresource *textureSubresource = VULKAN_INTERNAL_FetchTextureSubresource(
- textureContainer,
- layer,
- level);
- if (
- cycle &&
- textureContainer->canBeCycled &&
- SDL_GetAtomicInt(&textureContainer->activeTexture->referenceCount) > 0) {
- VULKAN_INTERNAL_CycleActiveTexture(
- renderer,
- commandBuffer,
- textureContainer);
- textureSubresource = VULKAN_INTERNAL_FetchTextureSubresource(
- textureContainer,
- layer,
- level);
- }
- // always do barrier because of layout transitions
- VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage(
- renderer,
- commandBuffer,
- destinationUsageMode,
- textureSubresource);
- return textureSubresource;
- }
- static VkRenderPass VULKAN_INTERNAL_CreateRenderPass(
- VulkanRenderer *renderer,
- const SDL_GPUColorTargetInfo *colorTargetInfos,
- Uint32 numColorTargets,
- const SDL_GPUDepthStencilTargetInfo *depthStencilTargetInfo)
- {
- VkResult vulkanResult;
- VkAttachmentDescription attachmentDescriptions[2 * MAX_COLOR_TARGET_BINDINGS + 1 /* depth */];
- VkAttachmentReference colorAttachmentReferences[MAX_COLOR_TARGET_BINDINGS];
- VkAttachmentReference resolveReferences[MAX_COLOR_TARGET_BINDINGS];
- VkAttachmentReference depthStencilAttachmentReference;
- VkRenderPassCreateInfo renderPassCreateInfo;
- VkSubpassDescription subpass;
- VkRenderPass renderPass;
- Uint32 i;
- Uint32 attachmentDescriptionCount = 0;
- Uint32 colorAttachmentReferenceCount = 0;
- Uint32 resolveReferenceCount = 0;
- for (i = 0; i < numColorTargets; i += 1) {
- VulkanTextureContainer *container = (VulkanTextureContainer *)colorTargetInfos[i].texture;
- attachmentDescriptions[attachmentDescriptionCount].flags = 0;
- attachmentDescriptions[attachmentDescriptionCount].format = SDLToVK_TextureFormat[container->header.info.format];
- attachmentDescriptions[attachmentDescriptionCount].samples = SDLToVK_SampleCount[container->header.info.sample_count];
- attachmentDescriptions[attachmentDescriptionCount].loadOp = SDLToVK_LoadOp[colorTargetInfos[i].load_op];
- attachmentDescriptions[attachmentDescriptionCount].storeOp = SDLToVK_StoreOp[colorTargetInfos[i].store_op];
- attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- attachmentDescriptions[attachmentDescriptionCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- attachmentDescriptions[attachmentDescriptionCount].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- attachmentDescriptions[attachmentDescriptionCount].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- colorAttachmentReferences[colorAttachmentReferenceCount].attachment = attachmentDescriptionCount;
- colorAttachmentReferences[colorAttachmentReferenceCount].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- attachmentDescriptionCount += 1;
- if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) {
- VulkanTextureContainer *resolveContainer = (VulkanTextureContainer *)colorTargetInfos[i].resolve_texture;
- attachmentDescriptions[attachmentDescriptionCount].flags = 0;
- attachmentDescriptions[attachmentDescriptionCount].format = SDLToVK_TextureFormat[resolveContainer->header.info.format];
- attachmentDescriptions[attachmentDescriptionCount].samples = SDLToVK_SampleCount[resolveContainer->header.info.sample_count];
- attachmentDescriptions[attachmentDescriptionCount].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; // The texture will be overwritten anyway
- attachmentDescriptions[attachmentDescriptionCount].storeOp = VK_ATTACHMENT_STORE_OP_STORE; // Always store the resolve texture
- attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- attachmentDescriptions[attachmentDescriptionCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- attachmentDescriptions[attachmentDescriptionCount].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- attachmentDescriptions[attachmentDescriptionCount].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- resolveReferences[colorAttachmentReferenceCount].attachment = attachmentDescriptionCount;
- resolveReferences[colorAttachmentReferenceCount].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- attachmentDescriptionCount += 1;
- resolveReferenceCount += 1;
- } else {
- resolveReferences[colorAttachmentReferenceCount].attachment = VK_ATTACHMENT_UNUSED;
- }
- colorAttachmentReferenceCount += 1;
- }
- subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
- subpass.flags = 0;
- subpass.inputAttachmentCount = 0;
- subpass.pInputAttachments = NULL;
- subpass.colorAttachmentCount = numColorTargets;
- subpass.pColorAttachments = colorAttachmentReferences;
- subpass.preserveAttachmentCount = 0;
- subpass.pPreserveAttachments = NULL;
- if (depthStencilTargetInfo == NULL) {
- subpass.pDepthStencilAttachment = NULL;
- } else {
- VulkanTextureContainer *container = (VulkanTextureContainer *)depthStencilTargetInfo->texture;
- attachmentDescriptions[attachmentDescriptionCount].flags = 0;
- attachmentDescriptions[attachmentDescriptionCount].format = SDLToVK_TextureFormat[container->header.info.format];
- attachmentDescriptions[attachmentDescriptionCount].samples = SDLToVK_SampleCount[container->header.info.sample_count];
- attachmentDescriptions[attachmentDescriptionCount].loadOp = SDLToVK_LoadOp[depthStencilTargetInfo->load_op];
- attachmentDescriptions[attachmentDescriptionCount].storeOp = SDLToVK_StoreOp[depthStencilTargetInfo->store_op];
- attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = SDLToVK_LoadOp[depthStencilTargetInfo->stencil_load_op];
- attachmentDescriptions[attachmentDescriptionCount].stencilStoreOp = SDLToVK_StoreOp[depthStencilTargetInfo->stencil_store_op];
- attachmentDescriptions[attachmentDescriptionCount].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
- attachmentDescriptions[attachmentDescriptionCount].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
- depthStencilAttachmentReference.attachment = attachmentDescriptionCount;
- depthStencilAttachmentReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
- subpass.pDepthStencilAttachment = &depthStencilAttachmentReference;
- attachmentDescriptionCount += 1;
- }
- if (resolveReferenceCount > 0) {
- subpass.pResolveAttachments = resolveReferences;
- } else {
- subpass.pResolveAttachments = NULL;
- }
- renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
- renderPassCreateInfo.pNext = NULL;
- renderPassCreateInfo.flags = 0;
- renderPassCreateInfo.pAttachments = attachmentDescriptions;
- renderPassCreateInfo.attachmentCount = attachmentDescriptionCount;
- renderPassCreateInfo.subpassCount = 1;
- renderPassCreateInfo.pSubpasses = &subpass;
- renderPassCreateInfo.dependencyCount = 0;
- renderPassCreateInfo.pDependencies = NULL;
- vulkanResult = renderer->vkCreateRenderPass(
- renderer->logicalDevice,
- &renderPassCreateInfo,
- NULL,
- &renderPass);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateRenderPass, VK_NULL_HANDLE);
- return renderPass;
- }
- static VkRenderPass VULKAN_INTERNAL_CreateTransientRenderPass(
- VulkanRenderer *renderer,
- SDL_GPUGraphicsPipelineTargetInfo targetInfo,
- VkSampleCountFlagBits sampleCount)
- {
- VkAttachmentDescription attachmentDescriptions[MAX_COLOR_TARGET_BINDINGS + 1 /* depth */];
- VkAttachmentReference colorAttachmentReferences[MAX_COLOR_TARGET_BINDINGS];
- VkAttachmentReference depthStencilAttachmentReference;
- SDL_GPUColorTargetDescription attachmentDescription;
- VkSubpassDescription subpass;
- VkRenderPassCreateInfo renderPassCreateInfo;
- VkRenderPass renderPass;
- VkResult result;
- Uint32 attachmentDescriptionCount = 0;
- Uint32 colorAttachmentReferenceCount = 0;
- Uint32 i;
- for (i = 0; i < targetInfo.num_color_targets; i += 1) {
- attachmentDescription = targetInfo.color_target_descriptions[i];
- attachmentDescriptions[attachmentDescriptionCount].flags = 0;
- attachmentDescriptions[attachmentDescriptionCount].format = SDLToVK_TextureFormat[attachmentDescription.format];
- attachmentDescriptions[attachmentDescriptionCount].samples = sampleCount;
- attachmentDescriptions[attachmentDescriptionCount].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- attachmentDescriptions[attachmentDescriptionCount].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- attachmentDescriptions[attachmentDescriptionCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- attachmentDescriptions[attachmentDescriptionCount].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- attachmentDescriptions[attachmentDescriptionCount].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- colorAttachmentReferences[colorAttachmentReferenceCount].attachment = attachmentDescriptionCount;
- colorAttachmentReferences[colorAttachmentReferenceCount].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- attachmentDescriptionCount += 1;
- colorAttachmentReferenceCount += 1;
- }
- subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
- subpass.flags = 0;
- subpass.inputAttachmentCount = 0;
- subpass.pInputAttachments = NULL;
- subpass.colorAttachmentCount = targetInfo.num_color_targets;
- subpass.pColorAttachments = colorAttachmentReferences;
- subpass.preserveAttachmentCount = 0;
- subpass.pPreserveAttachments = NULL;
- if (targetInfo.has_depth_stencil_target) {
- attachmentDescriptions[attachmentDescriptionCount].flags = 0;
- attachmentDescriptions[attachmentDescriptionCount].format = SDLToVK_TextureFormat[targetInfo.depth_stencil_format];
- attachmentDescriptions[attachmentDescriptionCount].samples = sampleCount;
- attachmentDescriptions[attachmentDescriptionCount].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- attachmentDescriptions[attachmentDescriptionCount].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- attachmentDescriptions[attachmentDescriptionCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- attachmentDescriptions[attachmentDescriptionCount].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
- attachmentDescriptions[attachmentDescriptionCount].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
- depthStencilAttachmentReference.attachment = attachmentDescriptionCount;
- depthStencilAttachmentReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
- subpass.pDepthStencilAttachment = &depthStencilAttachmentReference;
- attachmentDescriptionCount += 1;
- } else {
- subpass.pDepthStencilAttachment = NULL;
- }
- // Resolve attachments aren't needed for transient passes
- subpass.pResolveAttachments = NULL;
- renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
- renderPassCreateInfo.pNext = NULL;
- renderPassCreateInfo.flags = 0;
- renderPassCreateInfo.pAttachments = attachmentDescriptions;
- renderPassCreateInfo.attachmentCount = attachmentDescriptionCount;
- renderPassCreateInfo.subpassCount = 1;
- renderPassCreateInfo.pSubpasses = &subpass;
- renderPassCreateInfo.dependencyCount = 0;
- renderPassCreateInfo.pDependencies = NULL;
- result = renderer->vkCreateRenderPass(
- renderer->logicalDevice,
- &renderPassCreateInfo,
- NULL,
- &renderPass);
- CHECK_VULKAN_ERROR_AND_RETURN(result, vkCreateRenderPass, VK_NULL_HANDLE);
- return renderPass;
- }
- static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline(
- SDL_GPURenderer *driverData,
- const SDL_GPUGraphicsPipelineCreateInfo *createinfo)
- {
- VkResult vulkanResult;
- Uint32 i;
- VulkanGraphicsPipeline *graphicsPipeline = (VulkanGraphicsPipeline *)SDL_malloc(sizeof(VulkanGraphicsPipeline));
- VkGraphicsPipelineCreateInfo vkPipelineCreateInfo;
- VkPipelineShaderStageCreateInfo shaderStageCreateInfos[2];
- VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo;
- VkVertexInputBindingDescription *vertexInputBindingDescriptions = SDL_stack_alloc(VkVertexInputBindingDescription, createinfo->vertex_input_state.num_vertex_buffers);
- VkVertexInputAttributeDescription *vertexInputAttributeDescriptions = SDL_stack_alloc(VkVertexInputAttributeDescription, createinfo->vertex_input_state.num_vertex_attributes);
- VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo;
- VkPipelineViewportStateCreateInfo viewportStateCreateInfo;
- VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo;
- VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo;
- VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo;
- VkStencilOpState frontStencilState;
- VkStencilOpState backStencilState;
- VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo;
- VkPipelineColorBlendAttachmentState *colorBlendAttachmentStates = SDL_stack_alloc(
- VkPipelineColorBlendAttachmentState,
- createinfo->target_info.num_color_targets);
- static const VkDynamicState dynamicStates[] = {
- VK_DYNAMIC_STATE_VIEWPORT,
- VK_DYNAMIC_STATE_SCISSOR,
- VK_DYNAMIC_STATE_BLEND_CONSTANTS,
- VK_DYNAMIC_STATE_STENCIL_REFERENCE
- };
- VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo;
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- // Create a "compatible" render pass
- VkRenderPass transientRenderPass = VULKAN_INTERNAL_CreateTransientRenderPass(
- renderer,
- createinfo->target_info,
- SDLToVK_SampleCount[createinfo->multisample_state.sample_count]);
- // Dynamic state
- dynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
- dynamicStateCreateInfo.pNext = NULL;
- dynamicStateCreateInfo.flags = 0;
- dynamicStateCreateInfo.dynamicStateCount = SDL_arraysize(dynamicStates);
- dynamicStateCreateInfo.pDynamicStates = dynamicStates;
- // Shader stages
- graphicsPipeline->vertexShader = (VulkanShader *)createinfo->vertex_shader;
- SDL_AtomicIncRef(&graphicsPipeline->vertexShader->referenceCount);
- shaderStageCreateInfos[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- shaderStageCreateInfos[0].pNext = NULL;
- shaderStageCreateInfos[0].flags = 0;
- shaderStageCreateInfos[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
- shaderStageCreateInfos[0].module = graphicsPipeline->vertexShader->shaderModule;
- shaderStageCreateInfos[0].pName = graphicsPipeline->vertexShader->entrypointName;
- shaderStageCreateInfos[0].pSpecializationInfo = NULL;
- graphicsPipeline->fragmentShader = (VulkanShader *)createinfo->fragment_shader;
- SDL_AtomicIncRef(&graphicsPipeline->fragmentShader->referenceCount);
- shaderStageCreateInfos[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- shaderStageCreateInfos[1].pNext = NULL;
- shaderStageCreateInfos[1].flags = 0;
- shaderStageCreateInfos[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
- shaderStageCreateInfos[1].module = graphicsPipeline->fragmentShader->shaderModule;
- shaderStageCreateInfos[1].pName = graphicsPipeline->fragmentShader->entrypointName;
- shaderStageCreateInfos[1].pSpecializationInfo = NULL;
- if (renderer->debugMode) {
- if (graphicsPipeline->vertexShader->stage != SDL_GPU_SHADERSTAGE_VERTEX) {
- SDL_assert_release(!"CreateGraphicsPipeline was passed a fragment shader for the vertex stage");
- }
- if (graphicsPipeline->fragmentShader->stage != SDL_GPU_SHADERSTAGE_FRAGMENT) {
- SDL_assert_release(!"CreateGraphicsPipeline was passed a vertex shader for the fragment stage");
- }
- }
- // Vertex input
- for (i = 0; i < createinfo->vertex_input_state.num_vertex_buffers; i += 1) {
- vertexInputBindingDescriptions[i].binding = createinfo->vertex_input_state.vertex_buffer_descriptions[i].slot;
- vertexInputBindingDescriptions[i].inputRate = SDLToVK_VertexInputRate[createinfo->vertex_input_state.vertex_buffer_descriptions[i].input_rate];
- vertexInputBindingDescriptions[i].stride = createinfo->vertex_input_state.vertex_buffer_descriptions[i].pitch;
- }
- for (i = 0; i < createinfo->vertex_input_state.num_vertex_attributes; i += 1) {
- vertexInputAttributeDescriptions[i].binding = createinfo->vertex_input_state.vertex_attributes[i].buffer_slot;
- vertexInputAttributeDescriptions[i].format = SDLToVK_VertexFormat[createinfo->vertex_input_state.vertex_attributes[i].format];
- vertexInputAttributeDescriptions[i].location = createinfo->vertex_input_state.vertex_attributes[i].location;
- vertexInputAttributeDescriptions[i].offset = createinfo->vertex_input_state.vertex_attributes[i].offset;
- }
- vertexInputStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
- vertexInputStateCreateInfo.pNext = NULL;
- vertexInputStateCreateInfo.flags = 0;
- vertexInputStateCreateInfo.vertexBindingDescriptionCount = createinfo->vertex_input_state.num_vertex_buffers;
- vertexInputStateCreateInfo.pVertexBindingDescriptions = vertexInputBindingDescriptions;
- vertexInputStateCreateInfo.vertexAttributeDescriptionCount = createinfo->vertex_input_state.num_vertex_attributes;
- vertexInputStateCreateInfo.pVertexAttributeDescriptions = vertexInputAttributeDescriptions;
- // Topology
- inputAssemblyStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
- inputAssemblyStateCreateInfo.pNext = NULL;
- inputAssemblyStateCreateInfo.flags = 0;
- inputAssemblyStateCreateInfo.primitiveRestartEnable = VK_FALSE;
- inputAssemblyStateCreateInfo.topology = SDLToVK_PrimitiveType[createinfo->primitive_type];
- graphicsPipeline->primitiveType = createinfo->primitive_type;
- // Viewport
- // NOTE: viewport and scissor are dynamic, and must be set using the command buffer
- viewportStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
- viewportStateCreateInfo.pNext = NULL;
- viewportStateCreateInfo.flags = 0;
- viewportStateCreateInfo.viewportCount = 1;
- viewportStateCreateInfo.pViewports = NULL;
- viewportStateCreateInfo.scissorCount = 1;
- viewportStateCreateInfo.pScissors = NULL;
- // Rasterization
- rasterizationStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
- rasterizationStateCreateInfo.pNext = NULL;
- rasterizationStateCreateInfo.flags = 0;
- rasterizationStateCreateInfo.depthClampEnable = !createinfo->rasterizer_state.enable_depth_clip;
- rasterizationStateCreateInfo.rasterizerDiscardEnable = VK_FALSE;
- rasterizationStateCreateInfo.polygonMode = SDLToVK_PolygonMode(
- renderer,
- createinfo->rasterizer_state.fill_mode);
- rasterizationStateCreateInfo.cullMode = SDLToVK_CullMode[createinfo->rasterizer_state.cull_mode];
- rasterizationStateCreateInfo.frontFace = SDLToVK_FrontFace[createinfo->rasterizer_state.front_face];
- rasterizationStateCreateInfo.depthBiasEnable =
- createinfo->rasterizer_state.enable_depth_bias;
- rasterizationStateCreateInfo.depthBiasConstantFactor =
- createinfo->rasterizer_state.depth_bias_constant_factor;
- rasterizationStateCreateInfo.depthBiasClamp =
- createinfo->rasterizer_state.depth_bias_clamp;
- rasterizationStateCreateInfo.depthBiasSlopeFactor =
- createinfo->rasterizer_state.depth_bias_slope_factor;
- rasterizationStateCreateInfo.lineWidth = 1.0f;
- // Multisample
- Uint32 sampleMask = 0xFFFFFFFF;
- multisampleStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
- multisampleStateCreateInfo.pNext = NULL;
- multisampleStateCreateInfo.flags = 0;
- multisampleStateCreateInfo.rasterizationSamples = SDLToVK_SampleCount[createinfo->multisample_state.sample_count];
- multisampleStateCreateInfo.sampleShadingEnable = VK_FALSE;
- multisampleStateCreateInfo.minSampleShading = 1.0f;
- multisampleStateCreateInfo.pSampleMask = &sampleMask;
- multisampleStateCreateInfo.alphaToCoverageEnable = createinfo->multisample_state.enable_alpha_to_coverage;
- multisampleStateCreateInfo.alphaToOneEnable = VK_FALSE;
- // Depth Stencil State
- frontStencilState.failOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.front_stencil_state.fail_op];
- frontStencilState.passOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.front_stencil_state.pass_op];
- frontStencilState.depthFailOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.front_stencil_state.depth_fail_op];
- frontStencilState.compareOp = SDLToVK_CompareOp[createinfo->depth_stencil_state.front_stencil_state.compare_op];
- frontStencilState.compareMask =
- createinfo->depth_stencil_state.compare_mask;
- frontStencilState.writeMask =
- createinfo->depth_stencil_state.write_mask;
- frontStencilState.reference = 0;
- backStencilState.failOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.back_stencil_state.fail_op];
- backStencilState.passOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.back_stencil_state.pass_op];
- backStencilState.depthFailOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.back_stencil_state.depth_fail_op];
- backStencilState.compareOp = SDLToVK_CompareOp[createinfo->depth_stencil_state.back_stencil_state.compare_op];
- backStencilState.compareMask =
- createinfo->depth_stencil_state.compare_mask;
- backStencilState.writeMask =
- createinfo->depth_stencil_state.write_mask;
- backStencilState.reference = 0;
- depthStencilStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
- depthStencilStateCreateInfo.pNext = NULL;
- depthStencilStateCreateInfo.flags = 0;
- depthStencilStateCreateInfo.depthTestEnable =
- createinfo->depth_stencil_state.enable_depth_test;
- depthStencilStateCreateInfo.depthWriteEnable =
- createinfo->depth_stencil_state.enable_depth_write;
- depthStencilStateCreateInfo.depthCompareOp = SDLToVK_CompareOp[createinfo->depth_stencil_state.compare_op];
- depthStencilStateCreateInfo.depthBoundsTestEnable = VK_FALSE;
- depthStencilStateCreateInfo.stencilTestEnable =
- createinfo->depth_stencil_state.enable_stencil_test;
- depthStencilStateCreateInfo.front = frontStencilState;
- depthStencilStateCreateInfo.back = backStencilState;
- depthStencilStateCreateInfo.minDepthBounds = 0; // unused
- depthStencilStateCreateInfo.maxDepthBounds = 0; // unused
- // Color Blend
- for (i = 0; i < createinfo->target_info.num_color_targets; i += 1) {
- SDL_GPUColorTargetBlendState blendState = createinfo->target_info.color_target_descriptions[i].blend_state;
- SDL_GPUColorComponentFlags colorWriteMask = blendState.enable_color_write_mask ?
- blendState.color_write_mask :
- 0xF;
- colorBlendAttachmentStates[i].blendEnable =
- blendState.enable_blend;
- colorBlendAttachmentStates[i].srcColorBlendFactor = SDLToVK_BlendFactor[blendState.src_color_blendfactor];
- colorBlendAttachmentStates[i].dstColorBlendFactor = SDLToVK_BlendFactor[blendState.dst_color_blendfactor];
- colorBlendAttachmentStates[i].colorBlendOp = SDLToVK_BlendOp[blendState.color_blend_op];
- colorBlendAttachmentStates[i].srcAlphaBlendFactor = SDLToVK_BlendFactor[blendState.src_alpha_blendfactor];
- colorBlendAttachmentStates[i].dstAlphaBlendFactor = SDLToVK_BlendFactor[blendState.dst_alpha_blendfactor];
- colorBlendAttachmentStates[i].alphaBlendOp = SDLToVK_BlendOp[blendState.alpha_blend_op];
- colorBlendAttachmentStates[i].colorWriteMask =
- colorWriteMask;
- }
- colorBlendStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
- colorBlendStateCreateInfo.pNext = NULL;
- colorBlendStateCreateInfo.flags = 0;
- colorBlendStateCreateInfo.attachmentCount =
- createinfo->target_info.num_color_targets;
- colorBlendStateCreateInfo.pAttachments =
- colorBlendAttachmentStates;
- colorBlendStateCreateInfo.blendConstants[0] = 1.0f;
- colorBlendStateCreateInfo.blendConstants[1] = 1.0f;
- colorBlendStateCreateInfo.blendConstants[2] = 1.0f;
- colorBlendStateCreateInfo.blendConstants[3] = 1.0f;
- // We don't support LogicOp, so this is easy.
- colorBlendStateCreateInfo.logicOpEnable = VK_FALSE;
- colorBlendStateCreateInfo.logicOp = 0;
- // Pipeline Layout
- graphicsPipeline->resourceLayout =
- VULKAN_INTERNAL_FetchGraphicsPipelineResourceLayout(
- renderer,
- graphicsPipeline->vertexShader,
- graphicsPipeline->fragmentShader);
- if (graphicsPipeline->resourceLayout == NULL) {
- SDL_stack_free(vertexInputBindingDescriptions);
- SDL_stack_free(vertexInputAttributeDescriptions);
- SDL_stack_free(colorBlendAttachmentStates);
- SDL_free(graphicsPipeline);
- SET_STRING_ERROR_AND_RETURN("Failed to initialize pipeline resource layout!", NULL);
- }
- // Pipeline
- vkPipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
- vkPipelineCreateInfo.pNext = NULL;
- vkPipelineCreateInfo.flags = 0;
- vkPipelineCreateInfo.stageCount = 2;
- vkPipelineCreateInfo.pStages = shaderStageCreateInfos;
- vkPipelineCreateInfo.pVertexInputState = &vertexInputStateCreateInfo;
- vkPipelineCreateInfo.pInputAssemblyState = &inputAssemblyStateCreateInfo;
- vkPipelineCreateInfo.pTessellationState = VK_NULL_HANDLE;
- vkPipelineCreateInfo.pViewportState = &viewportStateCreateInfo;
- vkPipelineCreateInfo.pRasterizationState = &rasterizationStateCreateInfo;
- vkPipelineCreateInfo.pMultisampleState = &multisampleStateCreateInfo;
- vkPipelineCreateInfo.pDepthStencilState = &depthStencilStateCreateInfo;
- vkPipelineCreateInfo.pColorBlendState = &colorBlendStateCreateInfo;
- vkPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo;
- vkPipelineCreateInfo.layout = graphicsPipeline->resourceLayout->pipelineLayout;
- vkPipelineCreateInfo.renderPass = transientRenderPass;
- vkPipelineCreateInfo.subpass = 0;
- vkPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE;
- vkPipelineCreateInfo.basePipelineIndex = 0;
- // TODO: enable pipeline caching
- vulkanResult = renderer->vkCreateGraphicsPipelines(
- renderer->logicalDevice,
- VK_NULL_HANDLE,
- 1,
- &vkPipelineCreateInfo,
- NULL,
- &graphicsPipeline->pipeline);
- SDL_stack_free(vertexInputBindingDescriptions);
- SDL_stack_free(vertexInputAttributeDescriptions);
- SDL_stack_free(colorBlendAttachmentStates);
- renderer->vkDestroyRenderPass(
- renderer->logicalDevice,
- transientRenderPass,
- NULL);
- if (vulkanResult != VK_SUCCESS) {
- SDL_free(graphicsPipeline);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateGraphicsPipelines, NULL);
- }
- SDL_SetAtomicInt(&graphicsPipeline->referenceCount, 0);
- if (renderer->debugMode && renderer->supportsDebugUtils && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_GRAPHICSPIPELINE_CREATE_NAME_STRING)) {
- VkDebugUtilsObjectNameInfoEXT nameInfo;
- nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
- nameInfo.pNext = NULL;
- nameInfo.pObjectName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_GRAPHICSPIPELINE_CREATE_NAME_STRING, NULL);
- nameInfo.objectType = VK_OBJECT_TYPE_PIPELINE;
- nameInfo.objectHandle = (uint64_t)graphicsPipeline->pipeline;
- renderer->vkSetDebugUtilsObjectNameEXT(
- renderer->logicalDevice,
- &nameInfo);
- }
- // Put this data in the pipeline we can do validation in gpu.c
- graphicsPipeline->header.num_vertex_samplers = graphicsPipeline->resourceLayout->vertexSamplerCount;
- graphicsPipeline->header.num_vertex_storage_buffers = graphicsPipeline->resourceLayout->vertexStorageBufferCount;
- graphicsPipeline->header.num_vertex_storage_textures = graphicsPipeline->resourceLayout->vertexStorageTextureCount;
- graphicsPipeline->header.num_vertex_uniform_buffers = graphicsPipeline->resourceLayout->vertexUniformBufferCount;
- graphicsPipeline->header.num_fragment_samplers = graphicsPipeline->resourceLayout->fragmentSamplerCount;
- graphicsPipeline->header.num_fragment_storage_buffers = graphicsPipeline->resourceLayout->fragmentStorageBufferCount;
- graphicsPipeline->header.num_fragment_storage_textures = graphicsPipeline->resourceLayout->fragmentStorageTextureCount;
- graphicsPipeline->header.num_fragment_uniform_buffers = graphicsPipeline->resourceLayout->fragmentUniformBufferCount;
- return (SDL_GPUGraphicsPipeline *)graphicsPipeline;
- }
- static bool VULKAN_INTERNAL_IsValidShaderBytecode(
- const Uint8 *code,
- size_t codeSize)
- {
- // SPIR-V bytecode has a 4 byte header containing 0x07230203. SPIR-V is
- // defined as a stream of words and not a stream of bytes so both byte
- // orders need to be considered.
- //
- // FIXME: It is uncertain if drivers are able to load both byte orders. If
- // needed we may need to do an optional swizzle internally so apps can
- // continue to treat shader code as an opaque blob.
- if (codeSize < 4 || code == NULL) {
- return false;
- }
- const Uint32 magic = 0x07230203;
- const Uint32 magicInv = 0x03022307;
- return SDL_memcmp(code, &magic, 4) == 0 || SDL_memcmp(code, &magicInv, 4) == 0;
- }
- static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline(
- SDL_GPURenderer *driverData,
- const SDL_GPUComputePipelineCreateInfo *createinfo)
- {
- VkShaderModuleCreateInfo shaderModuleCreateInfo;
- VkComputePipelineCreateInfo vkShaderCreateInfo;
- VkPipelineShaderStageCreateInfo pipelineShaderStageCreateInfo;
- VkResult vulkanResult;
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- VulkanComputePipeline *vulkanComputePipeline;
- if (createinfo->format != SDL_GPU_SHADERFORMAT_SPIRV) {
- SET_STRING_ERROR_AND_RETURN("Incompatible shader format for Vulkan!", NULL);
- }
- if (!VULKAN_INTERNAL_IsValidShaderBytecode(createinfo->code, createinfo->code_size)) {
- SET_STRING_ERROR_AND_RETURN("The provided shader code is not valid SPIR-V!", NULL);
- }
- vulkanComputePipeline = SDL_malloc(sizeof(VulkanComputePipeline));
- shaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
- shaderModuleCreateInfo.pNext = NULL;
- shaderModuleCreateInfo.flags = 0;
- shaderModuleCreateInfo.codeSize = createinfo->code_size;
- shaderModuleCreateInfo.pCode = (Uint32 *)createinfo->code;
- vulkanResult = renderer->vkCreateShaderModule(
- renderer->logicalDevice,
- &shaderModuleCreateInfo,
- NULL,
- &vulkanComputePipeline->shaderModule);
- if (vulkanResult != VK_SUCCESS) {
- SDL_free(vulkanComputePipeline);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateShaderModule, NULL);
- }
- pipelineShaderStageCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- pipelineShaderStageCreateInfo.pNext = NULL;
- pipelineShaderStageCreateInfo.flags = 0;
- pipelineShaderStageCreateInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
- pipelineShaderStageCreateInfo.module = vulkanComputePipeline->shaderModule;
- pipelineShaderStageCreateInfo.pName = createinfo->entrypoint;
- pipelineShaderStageCreateInfo.pSpecializationInfo = NULL;
- vulkanComputePipeline->resourceLayout = VULKAN_INTERNAL_FetchComputePipelineResourceLayout(
- renderer,
- createinfo);
- if (vulkanComputePipeline->resourceLayout == NULL) {
- renderer->vkDestroyShaderModule(
- renderer->logicalDevice,
- vulkanComputePipeline->shaderModule,
- NULL);
- SDL_free(vulkanComputePipeline);
- return NULL;
- }
- vkShaderCreateInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
- vkShaderCreateInfo.pNext = NULL;
- vkShaderCreateInfo.flags = 0;
- vkShaderCreateInfo.stage = pipelineShaderStageCreateInfo;
- vkShaderCreateInfo.layout = vulkanComputePipeline->resourceLayout->pipelineLayout;
- vkShaderCreateInfo.basePipelineHandle = (VkPipeline)VK_NULL_HANDLE;
- vkShaderCreateInfo.basePipelineIndex = 0;
- vulkanResult = renderer->vkCreateComputePipelines(
- renderer->logicalDevice,
- (VkPipelineCache)VK_NULL_HANDLE,
- 1,
- &vkShaderCreateInfo,
- NULL,
- &vulkanComputePipeline->pipeline);
- if (vulkanResult != VK_SUCCESS) {
- VULKAN_INTERNAL_DestroyComputePipeline(renderer, vulkanComputePipeline);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateComputePipeline, NULL);
- return NULL;
- }
- SDL_SetAtomicInt(&vulkanComputePipeline->referenceCount, 0);
- if (renderer->debugMode && renderer->supportsDebugUtils && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_COMPUTEPIPELINE_CREATE_NAME_STRING)) {
- VkDebugUtilsObjectNameInfoEXT nameInfo;
- nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
- nameInfo.pNext = NULL;
- nameInfo.pObjectName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_COMPUTEPIPELINE_CREATE_NAME_STRING, NULL);
- nameInfo.objectType = VK_OBJECT_TYPE_PIPELINE;
- nameInfo.objectHandle = (uint64_t)vulkanComputePipeline->pipeline;
- renderer->vkSetDebugUtilsObjectNameEXT(
- renderer->logicalDevice,
- &nameInfo);
- }
- // Track these here for debug layer
- vulkanComputePipeline->header.numSamplers = vulkanComputePipeline->resourceLayout->numSamplers;
- vulkanComputePipeline->header.numReadonlyStorageTextures = vulkanComputePipeline->resourceLayout->numReadonlyStorageTextures;
- vulkanComputePipeline->header.numReadonlyStorageBuffers = vulkanComputePipeline->resourceLayout->numReadonlyStorageBuffers;
- vulkanComputePipeline->header.numReadWriteStorageTextures = vulkanComputePipeline->resourceLayout->numReadWriteStorageTextures;
- vulkanComputePipeline->header.numReadWriteStorageBuffers = vulkanComputePipeline->resourceLayout->numReadWriteStorageBuffers;
- vulkanComputePipeline->header.numUniformBuffers = vulkanComputePipeline->resourceLayout->numUniformBuffers;
- return (SDL_GPUComputePipeline *)vulkanComputePipeline;
- }
- static SDL_GPUSampler *VULKAN_CreateSampler(
- SDL_GPURenderer *driverData,
- const SDL_GPUSamplerCreateInfo *createinfo)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- VulkanSampler *vulkanSampler = SDL_malloc(sizeof(VulkanSampler));
- VkResult vulkanResult;
- VkSamplerCreateInfo vkSamplerCreateInfo;
- vkSamplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
- vkSamplerCreateInfo.pNext = NULL;
- vkSamplerCreateInfo.flags = 0;
- vkSamplerCreateInfo.magFilter = SDLToVK_Filter[createinfo->mag_filter];
- vkSamplerCreateInfo.minFilter = SDLToVK_Filter[createinfo->min_filter];
- vkSamplerCreateInfo.mipmapMode = SDLToVK_SamplerMipmapMode[createinfo->mipmap_mode];
- vkSamplerCreateInfo.addressModeU = SDLToVK_SamplerAddressMode[createinfo->address_mode_u];
- vkSamplerCreateInfo.addressModeV = SDLToVK_SamplerAddressMode[createinfo->address_mode_v];
- vkSamplerCreateInfo.addressModeW = SDLToVK_SamplerAddressMode[createinfo->address_mode_w];
- vkSamplerCreateInfo.mipLodBias = createinfo->mip_lod_bias;
- vkSamplerCreateInfo.anisotropyEnable = createinfo->enable_anisotropy;
- vkSamplerCreateInfo.maxAnisotropy = createinfo->max_anisotropy;
- vkSamplerCreateInfo.compareEnable = createinfo->enable_compare;
- vkSamplerCreateInfo.compareOp = SDLToVK_CompareOp[createinfo->compare_op];
- vkSamplerCreateInfo.minLod = createinfo->min_lod;
- vkSamplerCreateInfo.maxLod = createinfo->max_lod;
- vkSamplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; // arbitrary, unused
- vkSamplerCreateInfo.unnormalizedCoordinates = VK_FALSE;
- vulkanResult = renderer->vkCreateSampler(
- renderer->logicalDevice,
- &vkSamplerCreateInfo,
- NULL,
- &vulkanSampler->sampler);
- if (vulkanResult != VK_SUCCESS) {
- SDL_free(vulkanSampler);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSampler, NULL);
- }
- SDL_SetAtomicInt(&vulkanSampler->referenceCount, 0);
- if (renderer->debugMode && renderer->supportsDebugUtils && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_SAMPLER_CREATE_NAME_STRING)) {
- VkDebugUtilsObjectNameInfoEXT nameInfo;
- nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
- nameInfo.pNext = NULL;
- nameInfo.pObjectName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_SAMPLER_CREATE_NAME_STRING, NULL);
- nameInfo.objectType = VK_OBJECT_TYPE_SAMPLER;
- nameInfo.objectHandle = (uint64_t)vulkanSampler->sampler;
- renderer->vkSetDebugUtilsObjectNameEXT(
- renderer->logicalDevice,
- &nameInfo);
- }
- return (SDL_GPUSampler *)vulkanSampler;
- }
- static SDL_GPUShader *VULKAN_CreateShader(
- SDL_GPURenderer *driverData,
- const SDL_GPUShaderCreateInfo *createinfo)
- {
- VulkanShader *vulkanShader;
- VkResult vulkanResult;
- VkShaderModuleCreateInfo vkShaderModuleCreateInfo;
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- if (!VULKAN_INTERNAL_IsValidShaderBytecode(createinfo->code, createinfo->code_size)) {
- SET_STRING_ERROR_AND_RETURN("The provided shader code is not valid SPIR-V!", NULL);
- }
- vulkanShader = SDL_malloc(sizeof(VulkanShader));
- vkShaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
- vkShaderModuleCreateInfo.pNext = NULL;
- vkShaderModuleCreateInfo.flags = 0;
- vkShaderModuleCreateInfo.codeSize = createinfo->code_size;
- vkShaderModuleCreateInfo.pCode = (Uint32 *)createinfo->code;
- vulkanResult = renderer->vkCreateShaderModule(
- renderer->logicalDevice,
- &vkShaderModuleCreateInfo,
- NULL,
- &vulkanShader->shaderModule);
- if (vulkanResult != VK_SUCCESS) {
- SDL_free(vulkanShader);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateShaderModule, NULL);
- }
- const char *entrypoint = createinfo->entrypoint;
- if (!entrypoint) {
- entrypoint = "main";
- }
- vulkanShader->entrypointName = SDL_strdup(entrypoint);
- vulkanShader->stage = createinfo->stage;
- vulkanShader->numSamplers = createinfo->num_samplers;
- vulkanShader->numStorageTextures = createinfo->num_storage_textures;
- vulkanShader->numStorageBuffers = createinfo->num_storage_buffers;
- vulkanShader->numUniformBuffers = createinfo->num_uniform_buffers;
- SDL_SetAtomicInt(&vulkanShader->referenceCount, 0);
- if (renderer->debugMode && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_SHADER_CREATE_NAME_STRING)) {
- VkDebugUtilsObjectNameInfoEXT nameInfo;
- nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
- nameInfo.pNext = NULL;
- nameInfo.pObjectName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_SHADER_CREATE_NAME_STRING, NULL);
- nameInfo.objectType = VK_OBJECT_TYPE_SHADER_MODULE;
- nameInfo.objectHandle = (uint64_t)vulkanShader->shaderModule;
- renderer->vkSetDebugUtilsObjectNameEXT(
- renderer->logicalDevice,
- &nameInfo);
- }
- return (SDL_GPUShader *)vulkanShader;
- }
- static bool VULKAN_SupportsSampleCount(
- SDL_GPURenderer *driverData,
- SDL_GPUTextureFormat format,
- SDL_GPUSampleCount sampleCount)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- VkSampleCountFlags bits = IsDepthFormat(format) ? renderer->physicalDeviceProperties.properties.limits.framebufferDepthSampleCounts : renderer->physicalDeviceProperties.properties.limits.framebufferColorSampleCounts;
- VkSampleCountFlagBits vkSampleCount = SDLToVK_SampleCount[sampleCount];
- return !!(bits & vkSampleCount);
- }
- static SDL_GPUTexture *VULKAN_CreateTexture(
- SDL_GPURenderer *driverData,
- const SDL_GPUTextureCreateInfo *createinfo)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- VulkanTexture *texture;
- VulkanTextureContainer *container;
- texture = VULKAN_INTERNAL_CreateTexture(
- renderer,
- true,
- createinfo);
- if (texture == NULL) {
- return NULL;
- }
- container = SDL_malloc(sizeof(VulkanTextureContainer));
- // Copy properties so we don't lose information when the client destroys them
- container->header.info = *createinfo;
- container->header.info.props = SDL_CreateProperties();
- if (createinfo->props) {
- SDL_CopyProperties(createinfo->props, container->header.info.props);
- }
- container->canBeCycled = true;
- container->activeTexture = texture;
- container->textureCapacity = 1;
- container->textureCount = 1;
- container->textures = SDL_malloc(
- container->textureCapacity * sizeof(VulkanTexture *));
- container->textures[0] = container->activeTexture;
- container->debugName = NULL;
- if (SDL_HasProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING)) {
- container->debugName = SDL_strdup(SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING, NULL));
- }
- texture->container = container;
- texture->containerIndex = 0;
- return (SDL_GPUTexture *)container;
- }
- static SDL_GPUBuffer *VULKAN_CreateBuffer(
- SDL_GPURenderer *driverData,
- SDL_GPUBufferUsageFlags usageFlags,
- Uint32 size,
- const char *debugName)
- {
- return (SDL_GPUBuffer *)VULKAN_INTERNAL_CreateBufferContainer(
- (VulkanRenderer *)driverData,
- (VkDeviceSize)size,
- usageFlags,
- VULKAN_BUFFER_TYPE_GPU,
- false,
- debugName);
- }
- static VulkanUniformBuffer *VULKAN_INTERNAL_CreateUniformBuffer(
- VulkanRenderer *renderer,
- Uint32 size)
- {
- VulkanUniformBuffer *uniformBuffer = SDL_calloc(1, sizeof(VulkanUniformBuffer));
- uniformBuffer->buffer = VULKAN_INTERNAL_CreateBuffer(
- renderer,
- (VkDeviceSize)size,
- 0,
- VULKAN_BUFFER_TYPE_UNIFORM,
- false,
- NULL);
- uniformBuffer->drawOffset = 0;
- uniformBuffer->writeOffset = 0;
- uniformBuffer->buffer->uniformBufferForDefrag = uniformBuffer;
- return uniformBuffer;
- }
- static SDL_GPUTransferBuffer *VULKAN_CreateTransferBuffer(
- SDL_GPURenderer *driverData,
- SDL_GPUTransferBufferUsage usage,
- Uint32 size,
- const char *debugName)
- {
- return (SDL_GPUTransferBuffer *)VULKAN_INTERNAL_CreateBufferContainer(
- (VulkanRenderer *)driverData,
- (VkDeviceSize)size,
- 0,
- VULKAN_BUFFER_TYPE_TRANSFER,
- true, // Dedicated allocations preserve the data even if a defrag is triggered.
- debugName);
- }
- static void VULKAN_INTERNAL_ReleaseTexture(
- VulkanRenderer *renderer,
- VulkanTexture *vulkanTexture)
- {
- if (vulkanTexture->markedForDestroy) {
- return;
- }
- SDL_LockMutex(renderer->disposeLock);
- EXPAND_ARRAY_IF_NEEDED(
- renderer->texturesToDestroy,
- VulkanTexture *,
- renderer->texturesToDestroyCount + 1,
- renderer->texturesToDestroyCapacity,
- renderer->texturesToDestroyCapacity * 2);
- renderer->texturesToDestroy[renderer->texturesToDestroyCount] = vulkanTexture;
- renderer->texturesToDestroyCount += 1;
- vulkanTexture->markedForDestroy = true;
- SDL_UnlockMutex(renderer->disposeLock);
- }
- static void VULKAN_ReleaseTexture(
- SDL_GPURenderer *driverData,
- SDL_GPUTexture *texture)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- VulkanTextureContainer *vulkanTextureContainer = (VulkanTextureContainer *)texture;
- Uint32 i;
- SDL_LockMutex(renderer->disposeLock);
- for (i = 0; i < vulkanTextureContainer->textureCount; i += 1) {
- VULKAN_INTERNAL_ReleaseTexture(renderer, vulkanTextureContainer->textures[i]);
- }
- SDL_DestroyProperties(vulkanTextureContainer->header.info.props);
- // Containers are just client handles, so we can destroy immediately
- SDL_free(vulkanTextureContainer->debugName);
- SDL_free(vulkanTextureContainer->textures);
- SDL_free(vulkanTextureContainer);
- SDL_UnlockMutex(renderer->disposeLock);
- }
- static void VULKAN_ReleaseSampler(
- SDL_GPURenderer *driverData,
- SDL_GPUSampler *sampler)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- VulkanSampler *vulkanSampler = (VulkanSampler *)sampler;
- SDL_LockMutex(renderer->disposeLock);
- EXPAND_ARRAY_IF_NEEDED(
- renderer->samplersToDestroy,
- VulkanSampler *,
- renderer->samplersToDestroyCount + 1,
- renderer->samplersToDestroyCapacity,
- renderer->samplersToDestroyCapacity * 2);
- renderer->samplersToDestroy[renderer->samplersToDestroyCount] = vulkanSampler;
- renderer->samplersToDestroyCount += 1;
- SDL_UnlockMutex(renderer->disposeLock);
- }
- static void VULKAN_INTERNAL_ReleaseBuffer(
- VulkanRenderer *renderer,
- VulkanBuffer *vulkanBuffer)
- {
- if (vulkanBuffer->markedForDestroy) {
- return;
- }
- SDL_LockMutex(renderer->disposeLock);
- EXPAND_ARRAY_IF_NEEDED(
- renderer->buffersToDestroy,
- VulkanBuffer *,
- renderer->buffersToDestroyCount + 1,
- renderer->buffersToDestroyCapacity,
- renderer->buffersToDestroyCapacity * 2);
- renderer->buffersToDestroy[renderer->buffersToDestroyCount] = vulkanBuffer;
- renderer->buffersToDestroyCount += 1;
- vulkanBuffer->markedForDestroy = true;
- vulkanBuffer->container = NULL;
- SDL_UnlockMutex(renderer->disposeLock);
- }
- static void VULKAN_INTERNAL_ReleaseBufferContainer(
- VulkanRenderer *renderer,
- VulkanBufferContainer *bufferContainer)
- {
- Uint32 i;
- SDL_LockMutex(renderer->disposeLock);
- for (i = 0; i < bufferContainer->bufferCount; i += 1) {
- VULKAN_INTERNAL_ReleaseBuffer(renderer, bufferContainer->buffers[i]);
- }
- // Containers are just client handles, so we can free immediately
- if (bufferContainer->debugName != NULL) {
- SDL_free(bufferContainer->debugName);
- bufferContainer->debugName = NULL;
- }
- SDL_free(bufferContainer->buffers);
- SDL_free(bufferContainer);
- SDL_UnlockMutex(renderer->disposeLock);
- }
- static void VULKAN_ReleaseBuffer(
- SDL_GPURenderer *driverData,
- SDL_GPUBuffer *buffer)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- VulkanBufferContainer *vulkanBufferContainer = (VulkanBufferContainer *)buffer;
- VULKAN_INTERNAL_ReleaseBufferContainer(
- renderer,
- vulkanBufferContainer);
- }
- static void VULKAN_ReleaseTransferBuffer(
- SDL_GPURenderer *driverData,
- SDL_GPUTransferBuffer *transferBuffer)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)transferBuffer;
- VULKAN_INTERNAL_ReleaseBufferContainer(
- renderer,
- transferBufferContainer);
- }
- static void VULKAN_ReleaseShader(
- SDL_GPURenderer *driverData,
- SDL_GPUShader *shader)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- VulkanShader *vulkanShader = (VulkanShader *)shader;
- SDL_LockMutex(renderer->disposeLock);
- EXPAND_ARRAY_IF_NEEDED(
- renderer->shadersToDestroy,
- VulkanShader *,
- renderer->shadersToDestroyCount + 1,
- renderer->shadersToDestroyCapacity,
- renderer->shadersToDestroyCapacity * 2);
- renderer->shadersToDestroy[renderer->shadersToDestroyCount] = vulkanShader;
- renderer->shadersToDestroyCount += 1;
- SDL_UnlockMutex(renderer->disposeLock);
- }
- static void VULKAN_ReleaseComputePipeline(
- SDL_GPURenderer *driverData,
- SDL_GPUComputePipeline *computePipeline)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- VulkanComputePipeline *vulkanComputePipeline = (VulkanComputePipeline *)computePipeline;
- SDL_LockMutex(renderer->disposeLock);
- EXPAND_ARRAY_IF_NEEDED(
- renderer->computePipelinesToDestroy,
- VulkanComputePipeline *,
- renderer->computePipelinesToDestroyCount + 1,
- renderer->computePipelinesToDestroyCapacity,
- renderer->computePipelinesToDestroyCapacity * 2);
- renderer->computePipelinesToDestroy[renderer->computePipelinesToDestroyCount] = vulkanComputePipeline;
- renderer->computePipelinesToDestroyCount += 1;
- SDL_UnlockMutex(renderer->disposeLock);
- }
- static void VULKAN_ReleaseGraphicsPipeline(
- SDL_GPURenderer *driverData,
- SDL_GPUGraphicsPipeline *graphicsPipeline)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- VulkanGraphicsPipeline *vulkanGraphicsPipeline = (VulkanGraphicsPipeline *)graphicsPipeline;
- SDL_LockMutex(renderer->disposeLock);
- EXPAND_ARRAY_IF_NEEDED(
- renderer->graphicsPipelinesToDestroy,
- VulkanGraphicsPipeline *,
- renderer->graphicsPipelinesToDestroyCount + 1,
- renderer->graphicsPipelinesToDestroyCapacity,
- renderer->graphicsPipelinesToDestroyCapacity * 2);
- renderer->graphicsPipelinesToDestroy[renderer->graphicsPipelinesToDestroyCount] = vulkanGraphicsPipeline;
- renderer->graphicsPipelinesToDestroyCount += 1;
- SDL_UnlockMutex(renderer->disposeLock);
- }
- // Command Buffer render state
- static VkRenderPass VULKAN_INTERNAL_FetchRenderPass(
- VulkanRenderer *renderer,
- const SDL_GPUColorTargetInfo *colorTargetInfos,
- Uint32 numColorTargets,
- const SDL_GPUDepthStencilTargetInfo *depthStencilTargetInfo)
- {
- VulkanRenderPassHashTableValue *renderPassWrapper = NULL;
- VkRenderPass renderPassHandle;
- RenderPassHashTableKey key;
- Uint32 i;
- SDL_zero(key);
- for (i = 0; i < numColorTargets; i += 1) {
- key.colorTargetDescriptions[i].format = SDLToVK_TextureFormat[((VulkanTextureContainer *)colorTargetInfos[i].texture)->header.info.format];
- key.colorTargetDescriptions[i].loadOp = colorTargetInfos[i].load_op;
- key.colorTargetDescriptions[i].storeOp = colorTargetInfos[i].store_op;
- if (colorTargetInfos[i].resolve_texture != NULL) {
- key.resolveTargetFormats[key.numResolveTargets] = SDLToVK_TextureFormat[((VulkanTextureContainer *)colorTargetInfos[i].resolve_texture)->header.info.format];
- key.numResolveTargets += 1;
- }
- }
- key.sampleCount = VK_SAMPLE_COUNT_1_BIT;
- if (numColorTargets > 0) {
- key.sampleCount = SDLToVK_SampleCount[((VulkanTextureContainer *)colorTargetInfos[0].texture)->header.info.sample_count];
- } else if (numColorTargets == 0 && depthStencilTargetInfo != NULL) {
- key.sampleCount = SDLToVK_SampleCount[((VulkanTextureContainer *)depthStencilTargetInfo->texture)->header.info.sample_count];
- }
- key.numColorTargets = numColorTargets;
- if (depthStencilTargetInfo == NULL) {
- key.depthStencilTargetDescription.format = 0;
- key.depthStencilTargetDescription.loadOp = SDL_GPU_LOADOP_DONT_CARE;
- key.depthStencilTargetDescription.storeOp = SDL_GPU_STOREOP_DONT_CARE;
- key.depthStencilTargetDescription.stencilLoadOp = SDL_GPU_LOADOP_DONT_CARE;
- key.depthStencilTargetDescription.stencilStoreOp = SDL_GPU_STOREOP_DONT_CARE;
- } else {
- key.depthStencilTargetDescription.format = SDLToVK_TextureFormat[((VulkanTextureContainer *)depthStencilTargetInfo->texture)->header.info.format];
- key.depthStencilTargetDescription.loadOp = depthStencilTargetInfo->load_op;
- key.depthStencilTargetDescription.storeOp = depthStencilTargetInfo->store_op;
- key.depthStencilTargetDescription.stencilLoadOp = depthStencilTargetInfo->stencil_load_op;
- key.depthStencilTargetDescription.stencilStoreOp = depthStencilTargetInfo->stencil_store_op;
- }
- SDL_LockMutex(renderer->renderPassFetchLock);
- bool result = SDL_FindInHashTable(
- renderer->renderPassHashTable,
- (const void *)&key,
- (const void **)&renderPassWrapper);
- if (result) {
- SDL_UnlockMutex(renderer->renderPassFetchLock);
- return renderPassWrapper->handle;
- }
- renderPassHandle = VULKAN_INTERNAL_CreateRenderPass(
- renderer,
- colorTargetInfos,
- numColorTargets,
- depthStencilTargetInfo);
- if (renderPassHandle == VK_NULL_HANDLE) {
- SDL_UnlockMutex(renderer->renderPassFetchLock);
- return VK_NULL_HANDLE;
- }
- // Have to malloc the key to store it in the hashtable
- RenderPassHashTableKey *allocedKey = SDL_malloc(sizeof(RenderPassHashTableKey));
- SDL_memcpy(allocedKey, &key, sizeof(RenderPassHashTableKey));
- renderPassWrapper = SDL_malloc(sizeof(VulkanRenderPassHashTableValue));
- renderPassWrapper->handle = renderPassHandle;
- SDL_InsertIntoHashTable(
- renderer->renderPassHashTable,
- (const void *)allocedKey,
- (const void *)renderPassWrapper, true);
- SDL_UnlockMutex(renderer->renderPassFetchLock);
- return renderPassHandle;
- }
- static VulkanFramebuffer *VULKAN_INTERNAL_FetchFramebuffer(
- VulkanRenderer *renderer,
- VkRenderPass renderPass,
- const SDL_GPUColorTargetInfo *colorTargetInfos,
- Uint32 numColorTargets,
- const SDL_GPUDepthStencilTargetInfo *depthStencilTargetInfo,
- Uint32 width,
- Uint32 height)
- {
- VulkanFramebuffer *vulkanFramebuffer = NULL;
- VkFramebufferCreateInfo framebufferInfo;
- VkResult result;
- VkImageView imageViewAttachments[2 * MAX_COLOR_TARGET_BINDINGS + 1 /* depth */];
- FramebufferHashTableKey key;
- Uint32 attachmentCount = 0;
- Uint32 i;
- SDL_zero(imageViewAttachments);
- SDL_zero(key);
- key.numColorTargets = numColorTargets;
- for (i = 0; i < numColorTargets; i += 1) {
- VulkanTextureContainer *container = (VulkanTextureContainer *)colorTargetInfos[i].texture;
- VulkanTextureSubresource *subresource = VULKAN_INTERNAL_FetchTextureSubresource(
- container,
- container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : colorTargetInfos[i].layer_or_depth_plane,
- colorTargetInfos[i].mip_level);
- Uint32 rtvIndex =
- container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? colorTargetInfos[i].layer_or_depth_plane : 0;
- key.colorAttachmentViews[i] = subresource->renderTargetViews[rtvIndex];
- if (colorTargetInfos[i].resolve_texture != NULL) {
- VulkanTextureContainer *resolveTextureContainer = (VulkanTextureContainer *)colorTargetInfos[i].resolve_texture;
- VulkanTextureSubresource *resolveSubresource = VULKAN_INTERNAL_FetchTextureSubresource(
- resolveTextureContainer,
- colorTargetInfos[i].layer_or_depth_plane,
- colorTargetInfos[i].mip_level);
- key.resolveAttachmentViews[key.numResolveAttachments] = resolveSubresource->renderTargetViews[0];
- key.numResolveAttachments += 1;
- }
- }
- if (depthStencilTargetInfo == NULL) {
- key.depthStencilAttachmentView = VK_NULL_HANDLE;
- } else {
- VulkanTextureSubresource *subresource = VULKAN_INTERNAL_FetchTextureSubresource(
- (VulkanTextureContainer *)depthStencilTargetInfo->texture,
- depthStencilTargetInfo->layer,
- depthStencilTargetInfo->mip_level);
- key.depthStencilAttachmentView = subresource->depthStencilView;
- }
- key.width = width;
- key.height = height;
- SDL_LockMutex(renderer->framebufferFetchLock);
- bool findResult = SDL_FindInHashTable(
- renderer->framebufferHashTable,
- (const void *)&key,
- (const void **)&vulkanFramebuffer);
- if (findResult) {
- SDL_UnlockMutex(renderer->framebufferFetchLock);
- return vulkanFramebuffer;
- }
- vulkanFramebuffer = SDL_malloc(sizeof(VulkanFramebuffer));
- SDL_SetAtomicInt(&vulkanFramebuffer->referenceCount, 0);
- // Create a new framebuffer
- for (i = 0; i < numColorTargets; i += 1) {
- VulkanTextureContainer *container = (VulkanTextureContainer *)colorTargetInfos[i].texture;
- VulkanTextureSubresource *subresource = VULKAN_INTERNAL_FetchTextureSubresource(
- container,
- container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : colorTargetInfos[i].layer_or_depth_plane,
- colorTargetInfos[i].mip_level);
- Uint32 rtvIndex =
- container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? colorTargetInfos[i].layer_or_depth_plane : 0;
- imageViewAttachments[attachmentCount] = subresource->renderTargetViews[rtvIndex];
- attachmentCount += 1;
- if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) {
- VulkanTextureContainer *resolveContainer = (VulkanTextureContainer *)colorTargetInfos[i].resolve_texture;
- VulkanTextureSubresource *resolveSubresource = VULKAN_INTERNAL_FetchTextureSubresource(
- resolveContainer,
- colorTargetInfos[i].resolve_layer,
- colorTargetInfos[i].resolve_mip_level);
- imageViewAttachments[attachmentCount] = resolveSubresource->renderTargetViews[0];
- attachmentCount += 1;
- }
- }
- if (depthStencilTargetInfo != NULL) {
- VulkanTextureSubresource *subresource = VULKAN_INTERNAL_FetchTextureSubresource(
- (VulkanTextureContainer *)depthStencilTargetInfo->texture,
- depthStencilTargetInfo->layer,
- depthStencilTargetInfo->mip_level);
- imageViewAttachments[attachmentCount] = subresource->depthStencilView;
- attachmentCount += 1;
- }
- framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
- framebufferInfo.pNext = NULL;
- framebufferInfo.flags = 0;
- framebufferInfo.renderPass = renderPass;
- framebufferInfo.attachmentCount = attachmentCount;
- framebufferInfo.pAttachments = imageViewAttachments;
- framebufferInfo.width = key.width;
- framebufferInfo.height = key.height;
- framebufferInfo.layers = 1;
- result = renderer->vkCreateFramebuffer(
- renderer->logicalDevice,
- &framebufferInfo,
- NULL,
- &vulkanFramebuffer->framebuffer);
- if (result == VK_SUCCESS) {
- // Have to malloc the key to store it in the hashtable
- FramebufferHashTableKey *allocedKey = SDL_malloc(sizeof(FramebufferHashTableKey));
- SDL_memcpy(allocedKey, &key, sizeof(FramebufferHashTableKey));
- SDL_InsertIntoHashTable(
- renderer->framebufferHashTable,
- (const void *)allocedKey,
- (const void *)vulkanFramebuffer, true);
- } else {
- SDL_free(vulkanFramebuffer);
- SDL_UnlockMutex(renderer->framebufferFetchLock);
- CHECK_VULKAN_ERROR_AND_RETURN(result, vkCreateFramebuffer, NULL);
- }
- SDL_UnlockMutex(renderer->framebufferFetchLock);
- return vulkanFramebuffer;
- }
- static void VULKAN_INTERNAL_SetCurrentViewport(
- VulkanCommandBuffer *commandBuffer,
- const SDL_GPUViewport *viewport)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- vulkanCommandBuffer->currentViewport.x = viewport->x;
- vulkanCommandBuffer->currentViewport.width = viewport->w;
- vulkanCommandBuffer->currentViewport.minDepth = viewport->min_depth;
- vulkanCommandBuffer->currentViewport.maxDepth = viewport->max_depth;
- // Viewport flip for consistency with other backends
- vulkanCommandBuffer->currentViewport.y = viewport->y + viewport->h;
- vulkanCommandBuffer->currentViewport.height = -viewport->h;
- renderer->vkCmdSetViewport(
- vulkanCommandBuffer->commandBuffer,
- 0,
- 1,
- &vulkanCommandBuffer->currentViewport);
- }
- static void VULKAN_SetViewport(
- SDL_GPUCommandBuffer *commandBuffer,
- const SDL_GPUViewport *viewport)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VULKAN_INTERNAL_SetCurrentViewport(
- vulkanCommandBuffer,
- viewport);
- }
- static void VULKAN_INTERNAL_SetCurrentScissor(
- VulkanCommandBuffer *vulkanCommandBuffer,
- const SDL_Rect *scissor)
- {
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- vulkanCommandBuffer->currentScissor.offset.x = scissor->x;
- vulkanCommandBuffer->currentScissor.offset.y = scissor->y;
- vulkanCommandBuffer->currentScissor.extent.width = scissor->w;
- vulkanCommandBuffer->currentScissor.extent.height = scissor->h;
- renderer->vkCmdSetScissor(
- vulkanCommandBuffer->commandBuffer,
- 0,
- 1,
- &vulkanCommandBuffer->currentScissor);
- }
- static void VULKAN_SetScissor(
- SDL_GPUCommandBuffer *commandBuffer,
- const SDL_Rect *scissor)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VULKAN_INTERNAL_SetCurrentScissor(
- vulkanCommandBuffer,
- scissor);
- }
- static void VULKAN_INTERNAL_SetCurrentBlendConstants(
- VulkanCommandBuffer *vulkanCommandBuffer,
- SDL_FColor blendConstants)
- {
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- vulkanCommandBuffer->blendConstants[0] = blendConstants.r;
- vulkanCommandBuffer->blendConstants[1] = blendConstants.g;
- vulkanCommandBuffer->blendConstants[2] = blendConstants.b;
- vulkanCommandBuffer->blendConstants[3] = blendConstants.a;
- renderer->vkCmdSetBlendConstants(
- vulkanCommandBuffer->commandBuffer,
- vulkanCommandBuffer->blendConstants);
- }
- static void VULKAN_SetBlendConstants(
- SDL_GPUCommandBuffer *commandBuffer,
- SDL_FColor blendConstants)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VULKAN_INTERNAL_SetCurrentBlendConstants(
- vulkanCommandBuffer,
- blendConstants);
- }
- static void VULKAN_INTERNAL_SetCurrentStencilReference(
- VulkanCommandBuffer *vulkanCommandBuffer,
- Uint8 reference)
- {
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- vulkanCommandBuffer->stencilRef = reference;
- renderer->vkCmdSetStencilReference(
- vulkanCommandBuffer->commandBuffer,
- VK_STENCIL_FACE_FRONT_AND_BACK,
- vulkanCommandBuffer->stencilRef);
- }
- static void VULKAN_SetStencilReference(
- SDL_GPUCommandBuffer *commandBuffer,
- Uint8 reference)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VULKAN_INTERNAL_SetCurrentStencilReference(
- vulkanCommandBuffer,
- reference);
- }
- static void VULKAN_BindVertexSamplers(
- SDL_GPUCommandBuffer *commandBuffer,
- Uint32 firstSlot,
- const SDL_GPUTextureSamplerBinding *textureSamplerBindings,
- Uint32 numBindings)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- for (Uint32 i = 0; i < numBindings; i += 1) {
- VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)textureSamplerBindings[i].texture;
- VulkanSampler *sampler = (VulkanSampler *)textureSamplerBindings[i].sampler;
- if (vulkanCommandBuffer->vertexSamplerBindings[firstSlot + i] != sampler->sampler) {
- VULKAN_INTERNAL_TrackSampler(
- vulkanCommandBuffer,
- (VulkanSampler *)textureSamplerBindings[i].sampler);
- vulkanCommandBuffer->vertexSamplerBindings[firstSlot + i] = sampler->sampler;
- vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true;
- }
- if (vulkanCommandBuffer->vertexSamplerTextureViewBindings[firstSlot + i] != textureContainer->activeTexture->fullView) {
- VULKAN_INTERNAL_TrackTexture(
- vulkanCommandBuffer,
- textureContainer->activeTexture);
- vulkanCommandBuffer->vertexSamplerTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView;
- vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true;
- }
- }
- }
- static void VULKAN_BindVertexStorageTextures(
- SDL_GPUCommandBuffer *commandBuffer,
- Uint32 firstSlot,
- SDL_GPUTexture *const *storageTextures,
- Uint32 numBindings)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- for (Uint32 i = 0; i < numBindings; i += 1) {
- VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)storageTextures[i];
- if (vulkanCommandBuffer->vertexStorageTextureViewBindings[firstSlot + i] != textureContainer->activeTexture->fullView) {
- VULKAN_INTERNAL_TrackTexture(
- vulkanCommandBuffer,
- textureContainer->activeTexture);
- vulkanCommandBuffer->vertexStorageTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView;
- vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true;
- }
- }
- }
- static void VULKAN_BindVertexStorageBuffers(
- SDL_GPUCommandBuffer *commandBuffer,
- Uint32 firstSlot,
- SDL_GPUBuffer *const *storageBuffers,
- Uint32 numBindings)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- for (Uint32 i = 0; i < numBindings; i += 1) {
- VulkanBufferContainer *bufferContainer = (VulkanBufferContainer *)storageBuffers[i];
- if (vulkanCommandBuffer->vertexStorageBufferBindings[firstSlot + i] != bufferContainer->activeBuffer->buffer) {
- VULKAN_INTERNAL_TrackBuffer(
- vulkanCommandBuffer,
- bufferContainer->activeBuffer);
- vulkanCommandBuffer->vertexStorageBufferBindings[firstSlot + i] = bufferContainer->activeBuffer->buffer;
- vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true;
- }
- }
- }
- static void VULKAN_BindFragmentSamplers(
- SDL_GPUCommandBuffer *commandBuffer,
- Uint32 firstSlot,
- const SDL_GPUTextureSamplerBinding *textureSamplerBindings,
- Uint32 numBindings)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- for (Uint32 i = 0; i < numBindings; i += 1) {
- VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)textureSamplerBindings[i].texture;
- VulkanSampler *sampler = (VulkanSampler *)textureSamplerBindings[i].sampler;
- if (vulkanCommandBuffer->fragmentSamplerBindings[firstSlot + i] != sampler->sampler) {
- VULKAN_INTERNAL_TrackSampler(
- vulkanCommandBuffer,
- (VulkanSampler *)textureSamplerBindings[i].sampler);
- vulkanCommandBuffer->fragmentSamplerBindings[firstSlot + i] = sampler->sampler;
- vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true;
- }
- if (vulkanCommandBuffer->fragmentSamplerTextureViewBindings[firstSlot + i] != textureContainer->activeTexture->fullView) {
- VULKAN_INTERNAL_TrackTexture(
- vulkanCommandBuffer,
- textureContainer->activeTexture);
- vulkanCommandBuffer->fragmentSamplerTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView;
- vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true;
- }
- }
- }
- static void VULKAN_BindFragmentStorageTextures(
- SDL_GPUCommandBuffer *commandBuffer,
- Uint32 firstSlot,
- SDL_GPUTexture *const *storageTextures,
- Uint32 numBindings)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- for (Uint32 i = 0; i < numBindings; i += 1) {
- VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)storageTextures[i];
- if (vulkanCommandBuffer->fragmentStorageTextureViewBindings[firstSlot + i] != textureContainer->activeTexture->fullView) {
- VULKAN_INTERNAL_TrackTexture(
- vulkanCommandBuffer,
- textureContainer->activeTexture);
- vulkanCommandBuffer->fragmentStorageTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView;
- vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true;
- }
- }
- }
- static void VULKAN_BindFragmentStorageBuffers(
- SDL_GPUCommandBuffer *commandBuffer,
- Uint32 firstSlot,
- SDL_GPUBuffer *const *storageBuffers,
- Uint32 numBindings)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanBufferContainer *bufferContainer;
- Uint32 i;
- for (i = 0; i < numBindings; i += 1) {
- bufferContainer = (VulkanBufferContainer *)storageBuffers[i];
- if (vulkanCommandBuffer->fragmentStorageBufferBindings[firstSlot + i] != bufferContainer->activeBuffer->buffer) {
- VULKAN_INTERNAL_TrackBuffer(
- vulkanCommandBuffer,
- bufferContainer->activeBuffer);
- vulkanCommandBuffer->fragmentStorageBufferBindings[firstSlot + i] = bufferContainer->activeBuffer->buffer;
- vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true;
- }
- }
- }
- static VulkanUniformBuffer *VULKAN_INTERNAL_AcquireUniformBufferFromPool(
- VulkanCommandBuffer *commandBuffer)
- {
- VulkanRenderer *renderer = commandBuffer->renderer;
- VulkanUniformBuffer *uniformBuffer;
- SDL_LockMutex(renderer->acquireUniformBufferLock);
- if (renderer->uniformBufferPoolCount > 0) {
- uniformBuffer = renderer->uniformBufferPool[renderer->uniformBufferPoolCount - 1];
- renderer->uniformBufferPoolCount -= 1;
- } else {
- uniformBuffer = VULKAN_INTERNAL_CreateUniformBuffer(
- renderer,
- UNIFORM_BUFFER_SIZE);
- }
- SDL_UnlockMutex(renderer->acquireUniformBufferLock);
- VULKAN_INTERNAL_TrackUniformBuffer(commandBuffer, uniformBuffer);
- return uniformBuffer;
- }
- static void VULKAN_INTERNAL_ReturnUniformBufferToPool(
- VulkanRenderer *renderer,
- VulkanUniformBuffer *uniformBuffer)
- {
- if (renderer->uniformBufferPoolCount >= renderer->uniformBufferPoolCapacity) {
- renderer->uniformBufferPoolCapacity *= 2;
- renderer->uniformBufferPool = SDL_realloc(
- renderer->uniformBufferPool,
- renderer->uniformBufferPoolCapacity * sizeof(VulkanUniformBuffer *));
- }
- renderer->uniformBufferPool[renderer->uniformBufferPoolCount] = uniformBuffer;
- renderer->uniformBufferPoolCount += 1;
- uniformBuffer->writeOffset = 0;
- uniformBuffer->drawOffset = 0;
- }
- static void VULKAN_INTERNAL_PushUniformData(
- VulkanCommandBuffer *commandBuffer,
- VulkanUniformBufferStage uniformBufferStage,
- Uint32 slotIndex,
- const void *data,
- Uint32 length)
- {
- Uint32 blockSize =
- VULKAN_INTERNAL_NextHighestAlignment32(
- length,
- commandBuffer->renderer->minUBOAlignment);
- VulkanUniformBuffer *uniformBuffer;
- if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_VERTEX) {
- if (commandBuffer->vertexUniformBuffers[slotIndex] == NULL) {
- commandBuffer->vertexUniformBuffers[slotIndex] = VULKAN_INTERNAL_AcquireUniformBufferFromPool(
- commandBuffer);
- }
- uniformBuffer = commandBuffer->vertexUniformBuffers[slotIndex];
- } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_FRAGMENT) {
- if (commandBuffer->fragmentUniformBuffers[slotIndex] == NULL) {
- commandBuffer->fragmentUniformBuffers[slotIndex] = VULKAN_INTERNAL_AcquireUniformBufferFromPool(
- commandBuffer);
- }
- uniformBuffer = commandBuffer->fragmentUniformBuffers[slotIndex];
- } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_COMPUTE) {
- if (commandBuffer->computeUniformBuffers[slotIndex] == NULL) {
- commandBuffer->computeUniformBuffers[slotIndex] = VULKAN_INTERNAL_AcquireUniformBufferFromPool(
- commandBuffer);
- }
- uniformBuffer = commandBuffer->computeUniformBuffers[slotIndex];
- } else {
- SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized shader stage!");
- return;
- }
- // If there is no more room, acquire a new uniform buffer
- if (uniformBuffer->writeOffset + blockSize + MAX_UBO_SECTION_SIZE >= uniformBuffer->buffer->size) {
- uniformBuffer = VULKAN_INTERNAL_AcquireUniformBufferFromPool(commandBuffer);
- uniformBuffer->drawOffset = 0;
- uniformBuffer->writeOffset = 0;
- if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_VERTEX) {
- commandBuffer->vertexUniformBuffers[slotIndex] = uniformBuffer;
- commandBuffer->needNewVertexUniformDescriptorSet = true;
- } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_FRAGMENT) {
- commandBuffer->fragmentUniformBuffers[slotIndex] = uniformBuffer;
- commandBuffer->needNewFragmentUniformDescriptorSet = true;
- } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_COMPUTE) {
- commandBuffer->computeUniformBuffers[slotIndex] = uniformBuffer;
- commandBuffer->needNewComputeUniformDescriptorSet = true;
- } else {
- SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized shader stage!");
- return;
- }
- }
- uniformBuffer->drawOffset = uniformBuffer->writeOffset;
- Uint8 *dst =
- uniformBuffer->buffer->usedRegion->allocation->mapPointer +
- uniformBuffer->buffer->usedRegion->resourceOffset +
- uniformBuffer->writeOffset;
- SDL_memcpy(
- dst,
- data,
- length);
- uniformBuffer->writeOffset += blockSize;
- if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_VERTEX) {
- commandBuffer->needNewVertexUniformOffsets = true;
- } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_FRAGMENT) {
- commandBuffer->needNewFragmentUniformOffsets = true;
- } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_COMPUTE) {
- commandBuffer->needNewComputeUniformOffsets = true;
- } else {
- SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized shader stage!");
- return;
- }
- }
- static void VULKAN_BeginRenderPass(
- SDL_GPUCommandBuffer *commandBuffer,
- const SDL_GPUColorTargetInfo *colorTargetInfos,
- Uint32 numColorTargets,
- const SDL_GPUDepthStencilTargetInfo *depthStencilTargetInfo)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- VkRenderPass renderPass;
- VulkanFramebuffer *framebuffer;
- Uint32 w, h;
- VkClearValue *clearValues;
- Uint32 clearCount = 0;
- Uint32 totalColorAttachmentCount = 0;
- Uint32 i;
- SDL_GPUViewport defaultViewport;
- SDL_Rect defaultScissor;
- SDL_FColor defaultBlendConstants;
- Uint32 framebufferWidth = SDL_MAX_UINT32;
- Uint32 framebufferHeight = SDL_MAX_UINT32;
- for (i = 0; i < numColorTargets; i += 1) {
- VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)colorTargetInfos[i].texture;
- w = textureContainer->header.info.width >> colorTargetInfos[i].mip_level;
- h = textureContainer->header.info.height >> colorTargetInfos[i].mip_level;
- // The framebuffer cannot be larger than the smallest attachment.
- if (w < framebufferWidth) {
- framebufferWidth = w;
- }
- if (h < framebufferHeight) {
- framebufferHeight = h;
- }
- }
- if (depthStencilTargetInfo != NULL) {
- VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)depthStencilTargetInfo->texture;
- w = textureContainer->header.info.width >> depthStencilTargetInfo->mip_level;
- h = textureContainer->header.info.height >> depthStencilTargetInfo->mip_level;
- // The framebuffer cannot be larger than the smallest attachment.
- if (w < framebufferWidth) {
- framebufferWidth = w;
- }
- if (h < framebufferHeight) {
- framebufferHeight = h;
- }
- }
- for (i = 0; i < numColorTargets; i += 1) {
- VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)colorTargetInfos[i].texture;
- VulkanTextureSubresource *subresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite(
- renderer,
- vulkanCommandBuffer,
- textureContainer,
- textureContainer->header.info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : colorTargetInfos[i].layer_or_depth_plane,
- colorTargetInfos[i].mip_level,
- colorTargetInfos[i].cycle,
- VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT);
- vulkanCommandBuffer->colorAttachmentSubresources[vulkanCommandBuffer->colorAttachmentSubresourceCount] = subresource;
- vulkanCommandBuffer->colorAttachmentSubresourceCount += 1;
- VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, subresource->parent);
- totalColorAttachmentCount += 1;
- clearCount += 1;
- if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) {
- VulkanTextureContainer *resolveContainer = (VulkanTextureContainer *)colorTargetInfos[i].resolve_texture;
- VulkanTextureSubresource *resolveSubresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite(
- renderer,
- vulkanCommandBuffer,
- resolveContainer,
- colorTargetInfos[i].resolve_layer,
- colorTargetInfos[i].resolve_mip_level,
- colorTargetInfos[i].cycle_resolve_texture,
- VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT);
- vulkanCommandBuffer->resolveAttachmentSubresources[vulkanCommandBuffer->resolveAttachmentSubresourceCount] = resolveSubresource;
- vulkanCommandBuffer->resolveAttachmentSubresourceCount += 1;
- VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, resolveSubresource->parent);
- totalColorAttachmentCount += 1;
- clearCount += 1;
- }
- }
- if (depthStencilTargetInfo != NULL) {
- VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)depthStencilTargetInfo->texture;
- VulkanTextureSubresource *subresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite(
- renderer,
- vulkanCommandBuffer,
- textureContainer,
- depthStencilTargetInfo->layer,
- depthStencilTargetInfo->mip_level,
- depthStencilTargetInfo->cycle,
- VULKAN_TEXTURE_USAGE_MODE_DEPTH_STENCIL_ATTACHMENT);
- vulkanCommandBuffer->depthStencilAttachmentSubresource = subresource;
- VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, subresource->parent);
- clearCount += 1;
- }
- // Fetch required render objects
- renderPass = VULKAN_INTERNAL_FetchRenderPass(
- renderer,
- colorTargetInfos,
- numColorTargets,
- depthStencilTargetInfo);
- if (renderPass == VK_NULL_HANDLE) {
- return;
- }
- framebuffer = VULKAN_INTERNAL_FetchFramebuffer(
- renderer,
- renderPass,
- colorTargetInfos,
- numColorTargets,
- depthStencilTargetInfo,
- framebufferWidth,
- framebufferHeight);
- if (framebuffer == NULL) {
- return;
- }
- VULKAN_INTERNAL_TrackFramebuffer(vulkanCommandBuffer, framebuffer);
- // Set clear values
- clearValues = SDL_stack_alloc(VkClearValue, clearCount);
- int clearIndex = 0;
- for (i = 0; i < numColorTargets; i += 1) {
- clearValues[clearIndex].color.float32[0] = colorTargetInfos[i].clear_color.r;
- clearValues[clearIndex].color.float32[1] = colorTargetInfos[i].clear_color.g;
- clearValues[clearIndex].color.float32[2] = colorTargetInfos[i].clear_color.b;
- clearValues[clearIndex].color.float32[3] = colorTargetInfos[i].clear_color.a;
- clearIndex += 1;
- if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) {
- // Skip over the resolve texture, we're not clearing it
- clearIndex += 1;
- }
- }
- if (depthStencilTargetInfo != NULL) {
- clearValues[totalColorAttachmentCount].depthStencil.depth =
- depthStencilTargetInfo->clear_depth;
- clearValues[totalColorAttachmentCount].depthStencil.stencil =
- depthStencilTargetInfo->clear_stencil;
- }
- VkRenderPassBeginInfo renderPassBeginInfo;
- renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
- renderPassBeginInfo.pNext = NULL;
- renderPassBeginInfo.renderPass = renderPass;
- renderPassBeginInfo.framebuffer = framebuffer->framebuffer;
- renderPassBeginInfo.pClearValues = clearValues;
- renderPassBeginInfo.clearValueCount = clearCount;
- renderPassBeginInfo.renderArea.extent.width = framebufferWidth;
- renderPassBeginInfo.renderArea.extent.height = framebufferHeight;
- renderPassBeginInfo.renderArea.offset.x = 0;
- renderPassBeginInfo.renderArea.offset.y = 0;
- renderer->vkCmdBeginRenderPass(
- vulkanCommandBuffer->commandBuffer,
- &renderPassBeginInfo,
- VK_SUBPASS_CONTENTS_INLINE);
- SDL_stack_free(clearValues);
- // Set sensible default states
- defaultViewport.x = 0;
- defaultViewport.y = 0;
- defaultViewport.w = (float)framebufferWidth;
- defaultViewport.h = (float)framebufferHeight;
- defaultViewport.min_depth = 0;
- defaultViewport.max_depth = 1;
- VULKAN_INTERNAL_SetCurrentViewport(
- vulkanCommandBuffer,
- &defaultViewport);
- defaultScissor.x = 0;
- defaultScissor.y = 0;
- defaultScissor.w = (Sint32)framebufferWidth;
- defaultScissor.h = (Sint32)framebufferHeight;
- VULKAN_INTERNAL_SetCurrentScissor(
- vulkanCommandBuffer,
- &defaultScissor);
- defaultBlendConstants.r = 1.0f;
- defaultBlendConstants.g = 1.0f;
- defaultBlendConstants.b = 1.0f;
- defaultBlendConstants.a = 1.0f;
- VULKAN_INTERNAL_SetCurrentBlendConstants(
- vulkanCommandBuffer,
- defaultBlendConstants);
- VULKAN_INTERNAL_SetCurrentStencilReference(
- vulkanCommandBuffer,
- 0);
- }
- static void VULKAN_BindGraphicsPipeline(
- SDL_GPUCommandBuffer *commandBuffer,
- SDL_GPUGraphicsPipeline *graphicsPipeline)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- VulkanGraphicsPipeline *pipeline = (VulkanGraphicsPipeline *)graphicsPipeline;
- renderer->vkCmdBindPipeline(
- vulkanCommandBuffer->commandBuffer,
- VK_PIPELINE_BIND_POINT_GRAPHICS,
- pipeline->pipeline);
- vulkanCommandBuffer->currentGraphicsPipeline = pipeline;
- VULKAN_INTERNAL_TrackGraphicsPipeline(vulkanCommandBuffer, pipeline);
- // Acquire uniform buffers if necessary
- for (Uint32 i = 0; i < pipeline->resourceLayout->vertexUniformBufferCount; i += 1) {
- if (vulkanCommandBuffer->vertexUniformBuffers[i] == NULL) {
- vulkanCommandBuffer->vertexUniformBuffers[i] = VULKAN_INTERNAL_AcquireUniformBufferFromPool(
- vulkanCommandBuffer);
- }
- }
- for (Uint32 i = 0; i < pipeline->resourceLayout->fragmentUniformBufferCount; i += 1) {
- if (vulkanCommandBuffer->fragmentUniformBuffers[i] == NULL) {
- vulkanCommandBuffer->fragmentUniformBuffers[i] = VULKAN_INTERNAL_AcquireUniformBufferFromPool(
- vulkanCommandBuffer);
- }
- }
- // Mark bindings as needed
- vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true;
- vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true;
- vulkanCommandBuffer->needNewVertexUniformDescriptorSet = true;
- vulkanCommandBuffer->needNewFragmentUniformDescriptorSet = true;
- vulkanCommandBuffer->needNewVertexUniformOffsets = true;
- vulkanCommandBuffer->needNewFragmentUniformOffsets = true;
- }
- static void VULKAN_BindVertexBuffers(
- SDL_GPUCommandBuffer *commandBuffer,
- Uint32 firstSlot,
- const SDL_GPUBufferBinding *bindings,
- Uint32 numBindings)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- for (Uint32 i = 0; i < numBindings; i += 1) {
- VulkanBuffer *buffer = ((VulkanBufferContainer *)bindings[i].buffer)->activeBuffer;
- if (vulkanCommandBuffer->vertexBuffers[firstSlot + i] != buffer->buffer || vulkanCommandBuffer->vertexBufferOffsets[firstSlot + i] != bindings[i].offset) {
- VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, buffer);
- vulkanCommandBuffer->vertexBuffers[firstSlot + i] = buffer->buffer;
- vulkanCommandBuffer->vertexBufferOffsets[firstSlot + i] = bindings[i].offset;
- vulkanCommandBuffer->needVertexBufferBind = true;
- }
- }
- vulkanCommandBuffer->vertexBufferCount =
- SDL_max(vulkanCommandBuffer->vertexBufferCount, firstSlot + numBindings);
- }
- static void VULKAN_BindIndexBuffer(
- SDL_GPUCommandBuffer *commandBuffer,
- const SDL_GPUBufferBinding *binding,
- SDL_GPUIndexElementSize indexElementSize)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)binding->buffer)->activeBuffer;
- VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, vulkanBuffer);
- renderer->vkCmdBindIndexBuffer(
- vulkanCommandBuffer->commandBuffer,
- vulkanBuffer->buffer,
- (VkDeviceSize)binding->offset,
- SDLToVK_IndexType[indexElementSize]);
- }
- static void VULKAN_PushVertexUniformData(
- SDL_GPUCommandBuffer *commandBuffer,
- Uint32 slotIndex,
- const void *data,
- Uint32 length)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VULKAN_INTERNAL_PushUniformData(
- vulkanCommandBuffer,
- VULKAN_UNIFORM_BUFFER_STAGE_VERTEX,
- slotIndex,
- data,
- length);
- }
- static void VULKAN_PushFragmentUniformData(
- SDL_GPUCommandBuffer *commandBuffer,
- Uint32 slotIndex,
- const void *data,
- Uint32 length)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VULKAN_INTERNAL_PushUniformData(
- vulkanCommandBuffer,
- VULKAN_UNIFORM_BUFFER_STAGE_FRAGMENT,
- slotIndex,
- data,
- length);
- }
- static void VULKAN_EndRenderPass(
- SDL_GPUCommandBuffer *commandBuffer)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- Uint32 i;
- renderer->vkCmdEndRenderPass(
- vulkanCommandBuffer->commandBuffer);
- for (i = 0; i < vulkanCommandBuffer->colorAttachmentSubresourceCount; i += 1) {
- VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT,
- vulkanCommandBuffer->colorAttachmentSubresources[i]);
- }
- vulkanCommandBuffer->colorAttachmentSubresourceCount = 0;
- for (i = 0; i < vulkanCommandBuffer->resolveAttachmentSubresourceCount; i += 1) {
- VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT,
- vulkanCommandBuffer->resolveAttachmentSubresources[i]);
- }
- vulkanCommandBuffer->resolveAttachmentSubresourceCount = 0;
- if (vulkanCommandBuffer->depthStencilAttachmentSubresource != NULL) {
- VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_DEPTH_STENCIL_ATTACHMENT,
- vulkanCommandBuffer->depthStencilAttachmentSubresource);
- vulkanCommandBuffer->depthStencilAttachmentSubresource = NULL;
- }
- vulkanCommandBuffer->currentGraphicsPipeline = NULL;
- vulkanCommandBuffer->vertexResourceDescriptorSet = VK_NULL_HANDLE;
- vulkanCommandBuffer->vertexUniformDescriptorSet = VK_NULL_HANDLE;
- vulkanCommandBuffer->fragmentResourceDescriptorSet = VK_NULL_HANDLE;
- vulkanCommandBuffer->fragmentUniformDescriptorSet = VK_NULL_HANDLE;
- // Reset bind state
- SDL_zeroa(vulkanCommandBuffer->colorAttachmentSubresources);
- SDL_zeroa(vulkanCommandBuffer->resolveAttachmentSubresources);
- vulkanCommandBuffer->depthStencilAttachmentSubresource = NULL;
- SDL_zeroa(vulkanCommandBuffer->vertexBuffers);
- SDL_zeroa(vulkanCommandBuffer->vertexBufferOffsets);
- vulkanCommandBuffer->vertexBufferCount = 0;
- SDL_zeroa(vulkanCommandBuffer->vertexSamplerBindings);
- SDL_zeroa(vulkanCommandBuffer->vertexSamplerTextureViewBindings);
- SDL_zeroa(vulkanCommandBuffer->vertexStorageTextureViewBindings);
- SDL_zeroa(vulkanCommandBuffer->vertexStorageBufferBindings);
- SDL_zeroa(vulkanCommandBuffer->fragmentSamplerBindings);
- SDL_zeroa(vulkanCommandBuffer->fragmentSamplerTextureViewBindings);
- SDL_zeroa(vulkanCommandBuffer->fragmentStorageTextureViewBindings);
- SDL_zeroa(vulkanCommandBuffer->fragmentStorageBufferBindings);
- }
- static void VULKAN_BeginComputePass(
- SDL_GPUCommandBuffer *commandBuffer,
- const SDL_GPUStorageTextureReadWriteBinding *storageTextureBindings,
- Uint32 numStorageTextureBindings,
- const SDL_GPUStorageBufferReadWriteBinding *storageBufferBindings,
- Uint32 numStorageBufferBindings)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- VulkanBufferContainer *bufferContainer;
- VulkanBuffer *buffer;
- Uint32 i;
- vulkanCommandBuffer->readWriteComputeStorageTextureSubresourceCount = numStorageTextureBindings;
- for (i = 0; i < numStorageTextureBindings; i += 1) {
- VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)storageTextureBindings[i].texture;
- VulkanTextureSubresource *subresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite(
- renderer,
- vulkanCommandBuffer,
- textureContainer,
- storageTextureBindings[i].layer,
- storageTextureBindings[i].mip_level,
- storageTextureBindings[i].cycle,
- VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE);
- vulkanCommandBuffer->readWriteComputeStorageTextureSubresources[i] = subresource;
- vulkanCommandBuffer->readWriteComputeStorageTextureViewBindings[i] = subresource->computeWriteView;
- VULKAN_INTERNAL_TrackTexture(
- vulkanCommandBuffer,
- subresource->parent);
- }
- for (i = 0; i < numStorageBufferBindings; i += 1) {
- bufferContainer = (VulkanBufferContainer *)storageBufferBindings[i].buffer;
- buffer = VULKAN_INTERNAL_PrepareBufferForWrite(
- renderer,
- vulkanCommandBuffer,
- bufferContainer,
- storageBufferBindings[i].cycle,
- VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE);
- vulkanCommandBuffer->readWriteComputeStorageBuffers[i] = buffer;
- vulkanCommandBuffer->readWriteComputeStorageBufferBindings[i] = buffer->buffer;
- VULKAN_INTERNAL_TrackBuffer(
- vulkanCommandBuffer,
- buffer);
- }
- }
- static void VULKAN_BindComputePipeline(
- SDL_GPUCommandBuffer *commandBuffer,
- SDL_GPUComputePipeline *computePipeline)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- VulkanComputePipeline *vulkanComputePipeline = (VulkanComputePipeline *)computePipeline;
- renderer->vkCmdBindPipeline(
- vulkanCommandBuffer->commandBuffer,
- VK_PIPELINE_BIND_POINT_COMPUTE,
- vulkanComputePipeline->pipeline);
- vulkanCommandBuffer->currentComputePipeline = vulkanComputePipeline;
- VULKAN_INTERNAL_TrackComputePipeline(vulkanCommandBuffer, vulkanComputePipeline);
- // Acquire uniform buffers if necessary
- for (Uint32 i = 0; i < vulkanComputePipeline->resourceLayout->numUniformBuffers; i += 1) {
- if (vulkanCommandBuffer->computeUniformBuffers[i] == NULL) {
- vulkanCommandBuffer->computeUniformBuffers[i] = VULKAN_INTERNAL_AcquireUniformBufferFromPool(
- vulkanCommandBuffer);
- }
- }
- // Mark binding as needed
- vulkanCommandBuffer->needNewComputeReadWriteDescriptorSet = true;
- vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true;
- vulkanCommandBuffer->needNewComputeUniformDescriptorSet = true;
- vulkanCommandBuffer->needNewComputeUniformOffsets = true;
- }
- static void VULKAN_BindComputeSamplers(
- SDL_GPUCommandBuffer *commandBuffer,
- Uint32 firstSlot,
- const SDL_GPUTextureSamplerBinding *textureSamplerBindings,
- Uint32 numBindings)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- for (Uint32 i = 0; i < numBindings; i += 1) {
- VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)textureSamplerBindings[i].texture;
- VulkanSampler *sampler = (VulkanSampler *)textureSamplerBindings[i].sampler;
- if (vulkanCommandBuffer->computeSamplerBindings[firstSlot + i] != sampler->sampler) {
- VULKAN_INTERNAL_TrackSampler(
- vulkanCommandBuffer,
- sampler);
- vulkanCommandBuffer->computeSamplerBindings[firstSlot + i] = sampler->sampler;
- vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true;
- }
- if (vulkanCommandBuffer->computeSamplerTextureViewBindings[firstSlot + i] != textureContainer->activeTexture->fullView) {
- VULKAN_INTERNAL_TrackTexture(
- vulkanCommandBuffer,
- textureContainer->activeTexture);
- vulkanCommandBuffer->computeSamplerTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView;
- vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true;
- }
- }
- }
- static void VULKAN_BindComputeStorageTextures(
- SDL_GPUCommandBuffer *commandBuffer,
- Uint32 firstSlot,
- SDL_GPUTexture *const *storageTextures,
- Uint32 numBindings)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- for (Uint32 i = 0; i < numBindings; i += 1) {
- VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)storageTextures[i];
- if (vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i] != textureContainer->activeTexture) {
- /* If a different texture as in this slot, transition it back to its default usage */
- if (vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i] != NULL) {
- VULKAN_INTERNAL_TextureTransitionToDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ,
- vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i]);
- }
- /* Then transition the new texture and prepare it for binding */
- VULKAN_INTERNAL_TextureTransitionFromDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ,
- textureContainer->activeTexture);
- VULKAN_INTERNAL_TrackTexture(
- vulkanCommandBuffer,
- textureContainer->activeTexture);
- vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i] = textureContainer->activeTexture;
- vulkanCommandBuffer->readOnlyComputeStorageTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView;
- vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true;
- }
- }
- }
- static void VULKAN_BindComputeStorageBuffers(
- SDL_GPUCommandBuffer *commandBuffer,
- Uint32 firstSlot,
- SDL_GPUBuffer *const *storageBuffers,
- Uint32 numBindings)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- for (Uint32 i = 0; i < numBindings; i += 1) {
- VulkanBufferContainer *bufferContainer = (VulkanBufferContainer *)storageBuffers[i];
- if (vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i] != bufferContainer->activeBuffer) {
- /* If a different buffer was in this slot, transition it back to its default usage */
- if (vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i] != NULL) {
- VULKAN_INTERNAL_BufferTransitionToDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ,
- vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i]);
- }
- /* Then transition the new buffer and prepare it for binding */
- VULKAN_INTERNAL_BufferTransitionFromDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ,
- bufferContainer->activeBuffer);
- VULKAN_INTERNAL_TrackBuffer(
- vulkanCommandBuffer,
- bufferContainer->activeBuffer);
- vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i] = bufferContainer->activeBuffer;
- vulkanCommandBuffer->readOnlyComputeStorageBufferBindings[firstSlot + i] = bufferContainer->activeBuffer->buffer;
- vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true;
- }
- }
- }
- static void VULKAN_PushComputeUniformData(
- SDL_GPUCommandBuffer *commandBuffer,
- Uint32 slotIndex,
- const void *data,
- Uint32 length)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VULKAN_INTERNAL_PushUniformData(
- vulkanCommandBuffer,
- VULKAN_UNIFORM_BUFFER_STAGE_COMPUTE,
- slotIndex,
- data,
- length);
- }
- static void VULKAN_INTERNAL_BindComputeDescriptorSets(
- VulkanRenderer *renderer,
- VulkanCommandBuffer *commandBuffer)
- {
- VulkanComputePipelineResourceLayout *resourceLayout;
- DescriptorSetLayout *descriptorSetLayout;
- VkWriteDescriptorSet writeDescriptorSets[
- MAX_TEXTURE_SAMPLERS_PER_STAGE +
- MAX_STORAGE_TEXTURES_PER_STAGE +
- MAX_STORAGE_BUFFERS_PER_STAGE +
- MAX_COMPUTE_WRITE_TEXTURES +
- MAX_COMPUTE_WRITE_BUFFERS +
- MAX_UNIFORM_BUFFERS_PER_STAGE];
- VkDescriptorBufferInfo bufferInfos[MAX_STORAGE_BUFFERS_PER_STAGE + MAX_COMPUTE_WRITE_BUFFERS + MAX_UNIFORM_BUFFERS_PER_STAGE];
- VkDescriptorImageInfo imageInfos[MAX_TEXTURE_SAMPLERS_PER_STAGE + MAX_STORAGE_TEXTURES_PER_STAGE + MAX_COMPUTE_WRITE_TEXTURES];
- Uint32 dynamicOffsets[MAX_UNIFORM_BUFFERS_PER_STAGE];
- Uint32 writeCount = 0;
- Uint32 bufferInfoCount = 0;
- Uint32 imageInfoCount = 0;
- Uint32 dynamicOffsetCount = 0;
- if (
- !commandBuffer->needNewComputeReadOnlyDescriptorSet &&
- !commandBuffer->needNewComputeReadWriteDescriptorSet &&
- !commandBuffer->needNewComputeUniformDescriptorSet &&
- !commandBuffer->needNewComputeUniformOffsets
- ) {
- return;
- }
- resourceLayout = commandBuffer->currentComputePipeline->resourceLayout;
- if (commandBuffer->needNewComputeReadOnlyDescriptorSet) {
- descriptorSetLayout = resourceLayout->descriptorSetLayouts[0];
- commandBuffer->computeReadOnlyDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet(
- renderer,
- commandBuffer,
- descriptorSetLayout);
- for (Uint32 i = 0; i < resourceLayout->numSamplers; i += 1) {
- VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount];
- currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- currentWriteDescriptorSet->pNext = NULL;
- currentWriteDescriptorSet->descriptorCount = 1;
- currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
- currentWriteDescriptorSet->dstArrayElement = 0;
- currentWriteDescriptorSet->dstBinding = i;
- currentWriteDescriptorSet->dstSet = commandBuffer->computeReadOnlyDescriptorSet;
- currentWriteDescriptorSet->pTexelBufferView = NULL;
- currentWriteDescriptorSet->pBufferInfo = NULL;
- imageInfos[imageInfoCount].sampler = commandBuffer->computeSamplerBindings[i];
- imageInfos[imageInfoCount].imageView = commandBuffer->computeSamplerTextureViewBindings[i];
- imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount];
- writeCount += 1;
- imageInfoCount += 1;
- }
- for (Uint32 i = 0; i < resourceLayout->numReadonlyStorageTextures; i += 1) {
- VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount];
- currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- currentWriteDescriptorSet->pNext = NULL;
- currentWriteDescriptorSet->descriptorCount = 1;
- currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring the readonly storage texture as a sampled image, because shaders are stupid.
- currentWriteDescriptorSet->dstArrayElement = 0;
- currentWriteDescriptorSet->dstBinding = resourceLayout->numSamplers + i;
- currentWriteDescriptorSet->dstSet = commandBuffer->computeReadOnlyDescriptorSet;
- currentWriteDescriptorSet->pTexelBufferView = NULL;
- currentWriteDescriptorSet->pBufferInfo = NULL;
- imageInfos[imageInfoCount].sampler = VK_NULL_HANDLE;
- imageInfos[imageInfoCount].imageView = commandBuffer->readOnlyComputeStorageTextureViewBindings[i];
- imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
- currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount];
- writeCount += 1;
- imageInfoCount += 1;
- }
- for (Uint32 i = 0; i < resourceLayout->numReadonlyStorageBuffers; i += 1) {
- VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount];
- currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- currentWriteDescriptorSet->pNext = NULL;
- currentWriteDescriptorSet->descriptorCount = 1;
- currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- currentWriteDescriptorSet->dstArrayElement = 0;
- currentWriteDescriptorSet->dstBinding = resourceLayout->numSamplers + resourceLayout->numReadonlyStorageTextures + i;
- currentWriteDescriptorSet->dstSet = commandBuffer->computeReadOnlyDescriptorSet;
- currentWriteDescriptorSet->pTexelBufferView = NULL;
- currentWriteDescriptorSet->pImageInfo = NULL;
- bufferInfos[bufferInfoCount].buffer = commandBuffer->readOnlyComputeStorageBufferBindings[i];
- bufferInfos[bufferInfoCount].offset = 0;
- bufferInfos[bufferInfoCount].range = VK_WHOLE_SIZE;
- currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount];
- writeCount += 1;
- bufferInfoCount += 1;
- }
- commandBuffer->needNewComputeReadOnlyDescriptorSet = false;
- }
- if (commandBuffer->needNewComputeReadWriteDescriptorSet) {
- descriptorSetLayout = resourceLayout->descriptorSetLayouts[1];
- commandBuffer->computeReadWriteDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet(
- renderer,
- commandBuffer,
- descriptorSetLayout);
- for (Uint32 i = 0; i < resourceLayout->numReadWriteStorageTextures; i += 1) {
- VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount];
- currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- currentWriteDescriptorSet->pNext = NULL;
- currentWriteDescriptorSet->descriptorCount = 1;
- currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
- currentWriteDescriptorSet->dstArrayElement = 0;
- currentWriteDescriptorSet->dstBinding = i;
- currentWriteDescriptorSet->dstSet = commandBuffer->computeReadWriteDescriptorSet;
- currentWriteDescriptorSet->pTexelBufferView = NULL;
- currentWriteDescriptorSet->pBufferInfo = NULL;
- imageInfos[imageInfoCount].sampler = VK_NULL_HANDLE;
- imageInfos[imageInfoCount].imageView = commandBuffer->readWriteComputeStorageTextureViewBindings[i];
- imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
- currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount];
- writeCount += 1;
- imageInfoCount += 1;
- }
- for (Uint32 i = 0; i < resourceLayout->numReadWriteStorageBuffers; i += 1) {
- VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount];
- currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- currentWriteDescriptorSet->pNext = NULL;
- currentWriteDescriptorSet->descriptorCount = 1;
- currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- currentWriteDescriptorSet->dstArrayElement = 0;
- currentWriteDescriptorSet->dstBinding = resourceLayout->numReadWriteStorageTextures + i;
- currentWriteDescriptorSet->dstSet = commandBuffer->computeReadWriteDescriptorSet;
- currentWriteDescriptorSet->pTexelBufferView = NULL;
- currentWriteDescriptorSet->pImageInfo = NULL;
- bufferInfos[bufferInfoCount].buffer = commandBuffer->readWriteComputeStorageBufferBindings[i];
- bufferInfos[bufferInfoCount].offset = 0;
- bufferInfos[bufferInfoCount].range = VK_WHOLE_SIZE;
- currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount];
- writeCount += 1;
- bufferInfoCount += 1;
- }
- commandBuffer->needNewComputeReadWriteDescriptorSet = false;
- }
- if (commandBuffer->needNewComputeUniformDescriptorSet) {
- descriptorSetLayout = resourceLayout->descriptorSetLayouts[2];
- commandBuffer->computeUniformDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet(
- renderer,
- commandBuffer,
- descriptorSetLayout);
- for (Uint32 i = 0; i < resourceLayout->numUniformBuffers; i += 1) {
- VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount];
- currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- currentWriteDescriptorSet->pNext = NULL;
- currentWriteDescriptorSet->descriptorCount = 1;
- currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
- currentWriteDescriptorSet->dstArrayElement = 0;
- currentWriteDescriptorSet->dstBinding = i;
- currentWriteDescriptorSet->dstSet = commandBuffer->computeUniformDescriptorSet;
- currentWriteDescriptorSet->pTexelBufferView = NULL;
- currentWriteDescriptorSet->pImageInfo = NULL;
- bufferInfos[bufferInfoCount].buffer = commandBuffer->computeUniformBuffers[i]->buffer->buffer;
- bufferInfos[bufferInfoCount].offset = 0;
- bufferInfos[bufferInfoCount].range = MAX_UBO_SECTION_SIZE;
- currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount];
- writeCount += 1;
- bufferInfoCount += 1;
- }
- commandBuffer->needNewComputeUniformDescriptorSet = false;
- }
- for (Uint32 i = 0; i < resourceLayout->numUniformBuffers; i += 1) {
- dynamicOffsets[i] = commandBuffer->computeUniformBuffers[i]->drawOffset;
- dynamicOffsetCount += 1;
- }
- renderer->vkUpdateDescriptorSets(
- renderer->logicalDevice,
- writeCount,
- writeDescriptorSets,
- 0,
- NULL);
- VkDescriptorSet sets[3];
- sets[0] = commandBuffer->computeReadOnlyDescriptorSet;
- sets[1] = commandBuffer->computeReadWriteDescriptorSet;
- sets[2] = commandBuffer->computeUniformDescriptorSet;
- renderer->vkCmdBindDescriptorSets(
- commandBuffer->commandBuffer,
- VK_PIPELINE_BIND_POINT_COMPUTE,
- resourceLayout->pipelineLayout,
- 0,
- 3,
- sets,
- dynamicOffsetCount,
- dynamicOffsets);
- commandBuffer->needNewComputeUniformOffsets = false;
- }
- static void VULKAN_DispatchCompute(
- SDL_GPUCommandBuffer *commandBuffer,
- Uint32 groupcountX,
- Uint32 groupcountY,
- Uint32 groupcountZ)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- VULKAN_INTERNAL_BindComputeDescriptorSets(renderer, vulkanCommandBuffer);
- renderer->vkCmdDispatch(
- vulkanCommandBuffer->commandBuffer,
- groupcountX,
- groupcountY,
- groupcountZ);
- }
- static void VULKAN_DispatchComputeIndirect(
- SDL_GPUCommandBuffer *commandBuffer,
- SDL_GPUBuffer *buffer,
- Uint32 offset)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)buffer)->activeBuffer;
- VULKAN_INTERNAL_BindComputeDescriptorSets(renderer, vulkanCommandBuffer);
- renderer->vkCmdDispatchIndirect(
- vulkanCommandBuffer->commandBuffer,
- vulkanBuffer->buffer,
- offset);
- VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, vulkanBuffer);
- }
- static void VULKAN_EndComputePass(
- SDL_GPUCommandBuffer *commandBuffer)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- Uint32 i;
- for (i = 0; i < vulkanCommandBuffer->readWriteComputeStorageTextureSubresourceCount; i += 1) {
- VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
- vulkanCommandBuffer->renderer,
- vulkanCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE,
- vulkanCommandBuffer->readWriteComputeStorageTextureSubresources[i]);
- vulkanCommandBuffer->readWriteComputeStorageTextureSubresources[i] = NULL;
- }
- vulkanCommandBuffer->readWriteComputeStorageTextureSubresourceCount = 0;
- for (i = 0; i < MAX_COMPUTE_WRITE_BUFFERS; i += 1) {
- if (vulkanCommandBuffer->readWriteComputeStorageBuffers[i] != NULL) {
- VULKAN_INTERNAL_BufferTransitionToDefaultUsage(
- vulkanCommandBuffer->renderer,
- vulkanCommandBuffer,
- VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE,
- vulkanCommandBuffer->readWriteComputeStorageBuffers[i]);
- vulkanCommandBuffer->readWriteComputeStorageBuffers[i] = NULL;
- }
- }
- for (i = 0; i < MAX_STORAGE_TEXTURES_PER_STAGE; i += 1) {
- if (vulkanCommandBuffer->readOnlyComputeStorageTextures[i] != NULL) {
- VULKAN_INTERNAL_TextureTransitionToDefaultUsage(
- vulkanCommandBuffer->renderer,
- vulkanCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ,
- vulkanCommandBuffer->readOnlyComputeStorageTextures[i]);
- vulkanCommandBuffer->readOnlyComputeStorageTextures[i] = NULL;
- }
- }
- for (i = 0; i < MAX_STORAGE_BUFFERS_PER_STAGE; i += 1) {
- if (vulkanCommandBuffer->readOnlyComputeStorageBuffers[i] != NULL) {
- VULKAN_INTERNAL_BufferTransitionToDefaultUsage(
- vulkanCommandBuffer->renderer,
- vulkanCommandBuffer,
- VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ,
- vulkanCommandBuffer->readOnlyComputeStorageBuffers[i]);
- vulkanCommandBuffer->readOnlyComputeStorageBuffers[i] = NULL;
- }
- }
- // we don't need a barrier for sampler resources because sampler state is always the default if sampler bit is set
- SDL_zeroa(vulkanCommandBuffer->computeSamplerTextureViewBindings);
- SDL_zeroa(vulkanCommandBuffer->computeSamplerBindings);
- SDL_zeroa(vulkanCommandBuffer->readWriteComputeStorageTextureViewBindings);
- SDL_zeroa(vulkanCommandBuffer->readWriteComputeStorageBufferBindings);
- vulkanCommandBuffer->currentComputePipeline = NULL;
- vulkanCommandBuffer->computeReadOnlyDescriptorSet = VK_NULL_HANDLE;
- vulkanCommandBuffer->computeReadWriteDescriptorSet = VK_NULL_HANDLE;
- vulkanCommandBuffer->computeUniformDescriptorSet = VK_NULL_HANDLE;
- }
- static void *VULKAN_MapTransferBuffer(
- SDL_GPURenderer *driverData,
- SDL_GPUTransferBuffer *transferBuffer,
- bool cycle)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)transferBuffer;
- if (
- cycle &&
- SDL_GetAtomicInt(&transferBufferContainer->activeBuffer->referenceCount) > 0) {
- VULKAN_INTERNAL_CycleActiveBuffer(
- renderer,
- transferBufferContainer);
- }
- Uint8 *bufferPointer =
- transferBufferContainer->activeBuffer->usedRegion->allocation->mapPointer +
- transferBufferContainer->activeBuffer->usedRegion->resourceOffset;
- return bufferPointer;
- }
- static void VULKAN_UnmapTransferBuffer(
- SDL_GPURenderer *driverData,
- SDL_GPUTransferBuffer *transferBuffer)
- {
- // no-op because transfer buffers are persistently mapped
- (void)driverData;
- (void)transferBuffer;
- }
- static void VULKAN_BeginCopyPass(
- SDL_GPUCommandBuffer *commandBuffer)
- {
- // no-op
- (void)commandBuffer;
- }
- static void VULKAN_UploadToTexture(
- SDL_GPUCommandBuffer *commandBuffer,
- const SDL_GPUTextureTransferInfo *source,
- const SDL_GPUTextureRegion *destination,
- bool cycle)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)source->transfer_buffer;
- VulkanTextureContainer *vulkanTextureContainer = (VulkanTextureContainer *)destination->texture;
- VulkanTextureSubresource *vulkanTextureSubresource;
- VkBufferImageCopy imageCopy;
- // Note that the transfer buffer does not need a barrier, as it is synced by the client
- vulkanTextureSubresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite(
- renderer,
- vulkanCommandBuffer,
- vulkanTextureContainer,
- destination->layer,
- destination->mip_level,
- cycle,
- VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION);
- imageCopy.imageExtent.width = destination->w;
- imageCopy.imageExtent.height = destination->h;
- imageCopy.imageExtent.depth = destination->d;
- imageCopy.imageOffset.x = destination->x;
- imageCopy.imageOffset.y = destination->y;
- imageCopy.imageOffset.z = destination->z;
- imageCopy.imageSubresource.aspectMask = vulkanTextureSubresource->parent->aspectFlags;
- imageCopy.imageSubresource.baseArrayLayer = destination->layer;
- imageCopy.imageSubresource.layerCount = 1;
- imageCopy.imageSubresource.mipLevel = destination->mip_level;
- imageCopy.bufferOffset = source->offset;
- imageCopy.bufferRowLength = source->pixels_per_row;
- imageCopy.bufferImageHeight = source->rows_per_layer;
- renderer->vkCmdCopyBufferToImage(
- vulkanCommandBuffer->commandBuffer,
- transferBufferContainer->activeBuffer->buffer,
- vulkanTextureSubresource->parent->image,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- 1,
- &imageCopy);
- VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION,
- vulkanTextureSubresource);
- VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, transferBufferContainer->activeBuffer);
- VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, vulkanTextureSubresource->parent);
- }
- static void VULKAN_UploadToBuffer(
- SDL_GPUCommandBuffer *commandBuffer,
- const SDL_GPUTransferBufferLocation *source,
- const SDL_GPUBufferRegion *destination,
- bool cycle)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)source->transfer_buffer;
- VulkanBufferContainer *bufferContainer = (VulkanBufferContainer *)destination->buffer;
- VkBufferCopy bufferCopy;
- // Note that the transfer buffer does not need a barrier, as it is synced by the client
- VulkanBuffer *vulkanBuffer = VULKAN_INTERNAL_PrepareBufferForWrite(
- renderer,
- vulkanCommandBuffer,
- bufferContainer,
- cycle,
- VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION);
- bufferCopy.srcOffset = source->offset;
- bufferCopy.dstOffset = destination->offset;
- bufferCopy.size = destination->size;
- renderer->vkCmdCopyBuffer(
- vulkanCommandBuffer->commandBuffer,
- transferBufferContainer->activeBuffer->buffer,
- vulkanBuffer->buffer,
- 1,
- &bufferCopy);
- VULKAN_INTERNAL_BufferTransitionToDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION,
- vulkanBuffer);
- VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, transferBufferContainer->activeBuffer);
- VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, vulkanBuffer);
- }
- // Readback
- static void VULKAN_DownloadFromTexture(
- SDL_GPUCommandBuffer *commandBuffer,
- const SDL_GPUTextureRegion *source,
- const SDL_GPUTextureTransferInfo *destination)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)source->texture;
- VulkanTextureSubresource *vulkanTextureSubresource;
- VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)destination->transfer_buffer;
- VkBufferImageCopy imageCopy;
- vulkanTextureSubresource = VULKAN_INTERNAL_FetchTextureSubresource(
- textureContainer,
- source->layer,
- source->mip_level);
- // Note that the transfer buffer does not need a barrier, as it is synced by the client
- VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE,
- vulkanTextureSubresource);
- imageCopy.imageExtent.width = source->w;
- imageCopy.imageExtent.height = source->h;
- imageCopy.imageExtent.depth = source->d;
- imageCopy.imageOffset.x = source->x;
- imageCopy.imageOffset.y = source->y;
- imageCopy.imageOffset.z = source->z;
- imageCopy.imageSubresource.aspectMask = vulkanTextureSubresource->parent->aspectFlags;
- imageCopy.imageSubresource.baseArrayLayer = source->layer;
- imageCopy.imageSubresource.layerCount = 1;
- imageCopy.imageSubresource.mipLevel = source->mip_level;
- imageCopy.bufferOffset = destination->offset;
- imageCopy.bufferRowLength = destination->pixels_per_row;
- imageCopy.bufferImageHeight = destination->rows_per_layer;
- renderer->vkCmdCopyImageToBuffer(
- vulkanCommandBuffer->commandBuffer,
- vulkanTextureSubresource->parent->image,
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- transferBufferContainer->activeBuffer->buffer,
- 1,
- &imageCopy);
- VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE,
- vulkanTextureSubresource);
- VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, transferBufferContainer->activeBuffer);
- VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, vulkanTextureSubresource->parent);
- }
- static void VULKAN_DownloadFromBuffer(
- SDL_GPUCommandBuffer *commandBuffer,
- const SDL_GPUBufferRegion *source,
- const SDL_GPUTransferBufferLocation *destination)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- VulkanBufferContainer *bufferContainer = (VulkanBufferContainer *)source->buffer;
- VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)destination->transfer_buffer;
- VkBufferCopy bufferCopy;
- // Note that transfer buffer does not need a barrier, as it is synced by the client
- VULKAN_INTERNAL_BufferTransitionFromDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE,
- bufferContainer->activeBuffer);
- bufferCopy.srcOffset = source->offset;
- bufferCopy.dstOffset = destination->offset;
- bufferCopy.size = source->size;
- renderer->vkCmdCopyBuffer(
- vulkanCommandBuffer->commandBuffer,
- bufferContainer->activeBuffer->buffer,
- transferBufferContainer->activeBuffer->buffer,
- 1,
- &bufferCopy);
- VULKAN_INTERNAL_BufferTransitionToDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE,
- bufferContainer->activeBuffer);
- VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, transferBufferContainer->activeBuffer);
- VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, bufferContainer->activeBuffer);
- }
- static void VULKAN_CopyTextureToTexture(
- SDL_GPUCommandBuffer *commandBuffer,
- const SDL_GPUTextureLocation *source,
- const SDL_GPUTextureLocation *destination,
- Uint32 w,
- Uint32 h,
- Uint32 d,
- bool cycle)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- VulkanTextureSubresource *srcSubresource;
- VulkanTextureSubresource *dstSubresource;
- VkImageCopy imageCopy;
- srcSubresource = VULKAN_INTERNAL_FetchTextureSubresource(
- (VulkanTextureContainer *)source->texture,
- source->layer,
- source->mip_level);
- dstSubresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite(
- renderer,
- vulkanCommandBuffer,
- (VulkanTextureContainer *)destination->texture,
- destination->layer,
- destination->mip_level,
- cycle,
- VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION);
- VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE,
- srcSubresource);
- imageCopy.srcOffset.x = source->x;
- imageCopy.srcOffset.y = source->y;
- imageCopy.srcOffset.z = source->z;
- imageCopy.srcSubresource.aspectMask = srcSubresource->parent->aspectFlags;
- imageCopy.srcSubresource.baseArrayLayer = source->layer;
- imageCopy.srcSubresource.layerCount = 1;
- imageCopy.srcSubresource.mipLevel = source->mip_level;
- imageCopy.dstOffset.x = destination->x;
- imageCopy.dstOffset.y = destination->y;
- imageCopy.dstOffset.z = destination->z;
- imageCopy.dstSubresource.aspectMask = dstSubresource->parent->aspectFlags;
- imageCopy.dstSubresource.baseArrayLayer = destination->layer;
- imageCopy.dstSubresource.layerCount = 1;
- imageCopy.dstSubresource.mipLevel = destination->mip_level;
- imageCopy.extent.width = w;
- imageCopy.extent.height = h;
- imageCopy.extent.depth = d;
- renderer->vkCmdCopyImage(
- vulkanCommandBuffer->commandBuffer,
- srcSubresource->parent->image,
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- dstSubresource->parent->image,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- 1,
- &imageCopy);
- VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE,
- srcSubresource);
- VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION,
- dstSubresource);
- VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, srcSubresource->parent);
- VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, dstSubresource->parent);
- }
- static void VULKAN_CopyBufferToBuffer(
- SDL_GPUCommandBuffer *commandBuffer,
- const SDL_GPUBufferLocation *source,
- const SDL_GPUBufferLocation *destination,
- Uint32 size,
- bool cycle)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- VulkanBufferContainer *srcContainer = (VulkanBufferContainer *)source->buffer;
- VulkanBufferContainer *dstContainer = (VulkanBufferContainer *)destination->buffer;
- VkBufferCopy bufferCopy;
- VulkanBuffer *dstBuffer = VULKAN_INTERNAL_PrepareBufferForWrite(
- renderer,
- vulkanCommandBuffer,
- dstContainer,
- cycle,
- VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION);
- VULKAN_INTERNAL_BufferTransitionFromDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE,
- srcContainer->activeBuffer);
- bufferCopy.srcOffset = source->offset;
- bufferCopy.dstOffset = destination->offset;
- bufferCopy.size = size;
- renderer->vkCmdCopyBuffer(
- vulkanCommandBuffer->commandBuffer,
- srcContainer->activeBuffer->buffer,
- dstBuffer->buffer,
- 1,
- &bufferCopy);
- VULKAN_INTERNAL_BufferTransitionToDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE,
- srcContainer->activeBuffer);
- VULKAN_INTERNAL_BufferTransitionToDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION,
- dstBuffer);
- VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, srcContainer->activeBuffer);
- VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, dstBuffer);
- }
- static void VULKAN_GenerateMipmaps(
- SDL_GPUCommandBuffer *commandBuffer,
- SDL_GPUTexture *texture)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- VulkanTextureContainer *container = (VulkanTextureContainer *)texture;
- VulkanTextureSubresource *srcTextureSubresource;
- VulkanTextureSubresource *dstTextureSubresource;
- VkImageBlit blit;
- // Blit each slice sequentially. Barriers, barriers everywhere!
- for (Uint32 layerOrDepthIndex = 0; layerOrDepthIndex < container->header.info.layer_count_or_depth; layerOrDepthIndex += 1)
- for (Uint32 level = 1; level < container->header.info.num_levels; level += 1) {
- Uint32 layer = container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : layerOrDepthIndex;
- Uint32 depth = container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? layerOrDepthIndex : 0;
- Uint32 srcSubresourceIndex = VULKAN_INTERNAL_GetTextureSubresourceIndex(
- level - 1,
- layer,
- container->header.info.num_levels);
- Uint32 dstSubresourceIndex = VULKAN_INTERNAL_GetTextureSubresourceIndex(
- level,
- layer,
- container->header.info.num_levels);
- srcTextureSubresource = &container->activeTexture->subresources[srcSubresourceIndex];
- dstTextureSubresource = &container->activeTexture->subresources[dstSubresourceIndex];
- VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE,
- srcTextureSubresource);
- VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION,
- dstTextureSubresource);
- blit.srcOffsets[0].x = 0;
- blit.srcOffsets[0].y = 0;
- blit.srcOffsets[0].z = depth;
- blit.srcOffsets[1].x = container->header.info.width >> (level - 1);
- blit.srcOffsets[1].y = container->header.info.height >> (level - 1);
- blit.srcOffsets[1].z = depth + 1;
- blit.dstOffsets[0].x = 0;
- blit.dstOffsets[0].y = 0;
- blit.dstOffsets[0].z = depth;
- blit.dstOffsets[1].x = container->header.info.width >> level;
- blit.dstOffsets[1].y = container->header.info.height >> level;
- blit.dstOffsets[1].z = depth + 1;
- blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- blit.srcSubresource.baseArrayLayer = layer;
- blit.srcSubresource.layerCount = 1;
- blit.srcSubresource.mipLevel = level - 1;
- blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- blit.dstSubresource.baseArrayLayer = layer;
- blit.dstSubresource.layerCount = 1;
- blit.dstSubresource.mipLevel = level;
- renderer->vkCmdBlitImage(
- vulkanCommandBuffer->commandBuffer,
- container->activeTexture->image,
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- container->activeTexture->image,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- 1,
- &blit,
- VK_FILTER_LINEAR);
- VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE,
- srcTextureSubresource);
- VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION,
- dstTextureSubresource);
- VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, srcTextureSubresource->parent);
- VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, dstTextureSubresource->parent);
- }
- }
- static void VULKAN_EndCopyPass(
- SDL_GPUCommandBuffer *commandBuffer)
- {
- // no-op
- (void)commandBuffer;
- }
- static void VULKAN_Blit(
- SDL_GPUCommandBuffer *commandBuffer,
- const SDL_GPUBlitInfo *info)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- TextureCommonHeader *srcHeader = (TextureCommonHeader *)info->source.texture;
- TextureCommonHeader *dstHeader = (TextureCommonHeader *)info->destination.texture;
- VkImageBlit region;
- Uint32 srcLayer = srcHeader->info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : info->source.layer_or_depth_plane;
- Uint32 srcDepth = srcHeader->info.type == SDL_GPU_TEXTURETYPE_3D ? info->source.layer_or_depth_plane : 0;
- Uint32 dstLayer = dstHeader->info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : info->destination.layer_or_depth_plane;
- Uint32 dstDepth = dstHeader->info.type == SDL_GPU_TEXTURETYPE_3D ? info->destination.layer_or_depth_plane : 0;
- int32_t swap;
- // Using BeginRenderPass to clear because vkCmdClearColorImage requires barriers anyway
- if (info->load_op == SDL_GPU_LOADOP_CLEAR) {
- SDL_GPUColorTargetInfo targetInfo;
- SDL_zero(targetInfo);
- targetInfo.texture = info->destination.texture;
- targetInfo.mip_level = info->destination.mip_level;
- targetInfo.layer_or_depth_plane = info->destination.layer_or_depth_plane;
- targetInfo.load_op = SDL_GPU_LOADOP_CLEAR;
- targetInfo.store_op = SDL_GPU_STOREOP_STORE;
- targetInfo.clear_color = info->clear_color;
- targetInfo.cycle = info->cycle;
- VULKAN_BeginRenderPass(
- commandBuffer,
- &targetInfo,
- 1,
- NULL);
- VULKAN_EndRenderPass(commandBuffer);
- }
- VulkanTextureSubresource *srcSubresource = VULKAN_INTERNAL_FetchTextureSubresource(
- (VulkanTextureContainer *)info->source.texture,
- srcLayer,
- info->source.mip_level);
- VulkanTextureSubresource *dstSubresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite(
- renderer,
- vulkanCommandBuffer,
- (VulkanTextureContainer *)info->destination.texture,
- dstLayer,
- info->destination.mip_level,
- info->cycle,
- VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION);
- VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE,
- srcSubresource);
- region.srcSubresource.aspectMask = srcSubresource->parent->aspectFlags;
- region.srcSubresource.baseArrayLayer = srcSubresource->layer;
- region.srcSubresource.layerCount = 1;
- region.srcSubresource.mipLevel = srcSubresource->level;
- region.srcOffsets[0].x = info->source.x;
- region.srcOffsets[0].y = info->source.y;
- region.srcOffsets[0].z = srcDepth;
- region.srcOffsets[1].x = info->source.x + info->source.w;
- region.srcOffsets[1].y = info->source.y + info->source.h;
- region.srcOffsets[1].z = srcDepth + 1;
- if (info->flip_mode & SDL_FLIP_HORIZONTAL) {
- // flip the x positions
- swap = region.srcOffsets[0].x;
- region.srcOffsets[0].x = region.srcOffsets[1].x;
- region.srcOffsets[1].x = swap;
- }
- if (info->flip_mode & SDL_FLIP_VERTICAL) {
- // flip the y positions
- swap = region.srcOffsets[0].y;
- region.srcOffsets[0].y = region.srcOffsets[1].y;
- region.srcOffsets[1].y = swap;
- }
- region.dstSubresource.aspectMask = dstSubresource->parent->aspectFlags;
- region.dstSubresource.baseArrayLayer = dstSubresource->layer;
- region.dstSubresource.layerCount = 1;
- region.dstSubresource.mipLevel = dstSubresource->level;
- region.dstOffsets[0].x = info->destination.x;
- region.dstOffsets[0].y = info->destination.y;
- region.dstOffsets[0].z = dstDepth;
- region.dstOffsets[1].x = info->destination.x + info->destination.w;
- region.dstOffsets[1].y = info->destination.y + info->destination.h;
- region.dstOffsets[1].z = dstDepth + 1;
- renderer->vkCmdBlitImage(
- vulkanCommandBuffer->commandBuffer,
- srcSubresource->parent->image,
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- dstSubresource->parent->image,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- 1,
- ®ion,
- SDLToVK_Filter[info->filter]);
- VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE,
- srcSubresource);
- VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION,
- dstSubresource);
- VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, srcSubresource->parent);
- VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, dstSubresource->parent);
- }
- static bool VULKAN_INTERNAL_AllocateCommandBuffer(
- VulkanRenderer *renderer,
- VulkanCommandPool *vulkanCommandPool)
- {
- VkCommandBufferAllocateInfo allocateInfo;
- VkResult vulkanResult;
- VkCommandBuffer commandBufferHandle;
- VulkanCommandBuffer *commandBuffer;
- vulkanCommandPool->inactiveCommandBufferCapacity += 1;
- vulkanCommandPool->inactiveCommandBuffers = SDL_realloc(
- vulkanCommandPool->inactiveCommandBuffers,
- sizeof(VulkanCommandBuffer *) *
- vulkanCommandPool->inactiveCommandBufferCapacity);
- allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
- allocateInfo.pNext = NULL;
- allocateInfo.commandPool = vulkanCommandPool->commandPool;
- allocateInfo.commandBufferCount = 1;
- allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
- vulkanResult = renderer->vkAllocateCommandBuffers(
- renderer->logicalDevice,
- &allocateInfo,
- &commandBufferHandle);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkAllocateCommandBuffers, false);
- commandBuffer = SDL_malloc(sizeof(VulkanCommandBuffer));
- commandBuffer->renderer = renderer;
- commandBuffer->commandPool = vulkanCommandPool;
- commandBuffer->commandBuffer = commandBufferHandle;
- commandBuffer->inFlightFence = VK_NULL_HANDLE;
- // Presentation tracking
- commandBuffer->presentDataCapacity = 1;
- commandBuffer->presentDataCount = 0;
- commandBuffer->presentDatas = SDL_malloc(
- commandBuffer->presentDataCapacity * sizeof(VulkanPresentData));
- commandBuffer->waitSemaphoreCapacity = 1;
- commandBuffer->waitSemaphoreCount = 0;
- commandBuffer->waitSemaphores = SDL_malloc(
- commandBuffer->waitSemaphoreCapacity * sizeof(VkSemaphore));
- commandBuffer->signalSemaphoreCapacity = 1;
- commandBuffer->signalSemaphoreCount = 0;
- commandBuffer->signalSemaphores = SDL_malloc(
- commandBuffer->signalSemaphoreCapacity * sizeof(VkSemaphore));
- // Resource bind tracking
- commandBuffer->needVertexBufferBind = false;
- commandBuffer->needNewVertexResourceDescriptorSet = true;
- commandBuffer->needNewVertexUniformDescriptorSet = true;
- commandBuffer->needNewVertexUniformOffsets = true;
- commandBuffer->needNewFragmentResourceDescriptorSet = true;
- commandBuffer->needNewFragmentUniformDescriptorSet = true;
- commandBuffer->needNewFragmentUniformOffsets = true;
- commandBuffer->needNewComputeReadWriteDescriptorSet = true;
- commandBuffer->needNewComputeReadOnlyDescriptorSet = true;
- commandBuffer->needNewComputeUniformDescriptorSet = true;
- commandBuffer->needNewComputeUniformOffsets = true;
- commandBuffer->vertexResourceDescriptorSet = VK_NULL_HANDLE;
- commandBuffer->vertexUniformDescriptorSet = VK_NULL_HANDLE;
- commandBuffer->fragmentResourceDescriptorSet = VK_NULL_HANDLE;
- commandBuffer->fragmentUniformDescriptorSet = VK_NULL_HANDLE;
- commandBuffer->computeReadOnlyDescriptorSet = VK_NULL_HANDLE;
- commandBuffer->computeReadWriteDescriptorSet = VK_NULL_HANDLE;
- commandBuffer->computeUniformDescriptorSet = VK_NULL_HANDLE;
- // Resource tracking
- commandBuffer->usedBufferCapacity = 4;
- commandBuffer->usedBufferCount = 0;
- commandBuffer->usedBuffers = SDL_malloc(
- commandBuffer->usedBufferCapacity * sizeof(VulkanBuffer *));
- commandBuffer->usedTextureCapacity = 4;
- commandBuffer->usedTextureCount = 0;
- commandBuffer->usedTextures = SDL_malloc(
- commandBuffer->usedTextureCapacity * sizeof(VulkanTexture *));
- commandBuffer->usedSamplerCapacity = 4;
- commandBuffer->usedSamplerCount = 0;
- commandBuffer->usedSamplers = SDL_malloc(
- commandBuffer->usedSamplerCapacity * sizeof(VulkanSampler *));
- commandBuffer->usedGraphicsPipelineCapacity = 4;
- commandBuffer->usedGraphicsPipelineCount = 0;
- commandBuffer->usedGraphicsPipelines = SDL_malloc(
- commandBuffer->usedGraphicsPipelineCapacity * sizeof(VulkanGraphicsPipeline *));
- commandBuffer->usedComputePipelineCapacity = 4;
- commandBuffer->usedComputePipelineCount = 0;
- commandBuffer->usedComputePipelines = SDL_malloc(
- commandBuffer->usedComputePipelineCapacity * sizeof(VulkanComputePipeline *));
- commandBuffer->usedFramebufferCapacity = 4;
- commandBuffer->usedFramebufferCount = 0;
- commandBuffer->usedFramebuffers = SDL_malloc(
- commandBuffer->usedFramebufferCapacity * sizeof(VulkanFramebuffer *));
- commandBuffer->usedUniformBufferCapacity = 4;
- commandBuffer->usedUniformBufferCount = 0;
- commandBuffer->usedUniformBuffers = SDL_malloc(
- commandBuffer->usedUniformBufferCapacity * sizeof(VulkanUniformBuffer *));
- commandBuffer->swapchainRequested = false;
- // Pool it!
- vulkanCommandPool->inactiveCommandBuffers[vulkanCommandPool->inactiveCommandBufferCount] = commandBuffer;
- vulkanCommandPool->inactiveCommandBufferCount += 1;
- return true;
- }
- static VulkanCommandPool *VULKAN_INTERNAL_FetchCommandPool(
- VulkanRenderer *renderer,
- SDL_ThreadID threadID)
- {
- VulkanCommandPool *vulkanCommandPool = NULL;
- VkCommandPoolCreateInfo commandPoolCreateInfo;
- VkResult vulkanResult;
- CommandPoolHashTableKey key;
- key.threadID = threadID;
- bool result = SDL_FindInHashTable(
- renderer->commandPoolHashTable,
- (const void *)&key,
- (const void **)&vulkanCommandPool);
- if (result) {
- return vulkanCommandPool;
- }
- vulkanCommandPool = (VulkanCommandPool *)SDL_malloc(sizeof(VulkanCommandPool));
- commandPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
- commandPoolCreateInfo.pNext = NULL;
- commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
- commandPoolCreateInfo.queueFamilyIndex = renderer->queueFamilyIndex;
- vulkanResult = renderer->vkCreateCommandPool(
- renderer->logicalDevice,
- &commandPoolCreateInfo,
- NULL,
- &vulkanCommandPool->commandPool);
- if (vulkanResult != VK_SUCCESS) {
- SDL_free(vulkanCommandPool);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateCommandPool, NULL);
- return NULL;
- }
- vulkanCommandPool->threadID = threadID;
- vulkanCommandPool->inactiveCommandBufferCapacity = 0;
- vulkanCommandPool->inactiveCommandBufferCount = 0;
- vulkanCommandPool->inactiveCommandBuffers = NULL;
- if (!VULKAN_INTERNAL_AllocateCommandBuffer(
- renderer,
- vulkanCommandPool)) {
- VULKAN_INTERNAL_DestroyCommandPool(renderer, vulkanCommandPool);
- return NULL;
- }
- CommandPoolHashTableKey *allocedKey = SDL_malloc(sizeof(CommandPoolHashTableKey));
- allocedKey->threadID = threadID;
- SDL_InsertIntoHashTable(
- renderer->commandPoolHashTable,
- (const void *)allocedKey,
- (const void *)vulkanCommandPool, true);
- return vulkanCommandPool;
- }
- static VulkanCommandBuffer *VULKAN_INTERNAL_GetInactiveCommandBufferFromPool(
- VulkanRenderer *renderer,
- SDL_ThreadID threadID)
- {
- VulkanCommandPool *commandPool =
- VULKAN_INTERNAL_FetchCommandPool(renderer, threadID);
- VulkanCommandBuffer *commandBuffer;
- if (commandPool == NULL) {
- return NULL;
- }
- if (commandPool->inactiveCommandBufferCount == 0) {
- if (!VULKAN_INTERNAL_AllocateCommandBuffer(
- renderer,
- commandPool)) {
- return NULL;
- }
- }
- commandBuffer = commandPool->inactiveCommandBuffers[commandPool->inactiveCommandBufferCount - 1];
- commandPool->inactiveCommandBufferCount -= 1;
- return commandBuffer;
- }
- static SDL_GPUCommandBuffer *VULKAN_AcquireCommandBuffer(
- SDL_GPURenderer *driverData)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- VkResult result;
- Uint32 i;
- SDL_ThreadID threadID = SDL_GetCurrentThreadID();
- SDL_LockMutex(renderer->acquireCommandBufferLock);
- VulkanCommandBuffer *commandBuffer =
- VULKAN_INTERNAL_GetInactiveCommandBufferFromPool(renderer, threadID);
- DescriptorSetCache *descriptorSetCache =
- VULKAN_INTERNAL_AcquireDescriptorSetCache(renderer);
- SDL_UnlockMutex(renderer->acquireCommandBufferLock);
- if (commandBuffer == NULL) {
- return NULL;
- }
- commandBuffer->descriptorSetCache = descriptorSetCache;
- // Reset state
- commandBuffer->currentComputePipeline = NULL;
- commandBuffer->currentGraphicsPipeline = NULL;
- SDL_zeroa(commandBuffer->colorAttachmentSubresources);
- SDL_zeroa(commandBuffer->resolveAttachmentSubresources);
- commandBuffer->depthStencilAttachmentSubresource = NULL;
- commandBuffer->colorAttachmentSubresourceCount = 0;
- commandBuffer->resolveAttachmentSubresourceCount = 0;
- for (i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) {
- commandBuffer->vertexUniformBuffers[i] = NULL;
- commandBuffer->fragmentUniformBuffers[i] = NULL;
- commandBuffer->computeUniformBuffers[i] = NULL;
- }
- commandBuffer->needVertexBufferBind = false;
- commandBuffer->needNewVertexResourceDescriptorSet = true;
- commandBuffer->needNewVertexUniformDescriptorSet = true;
- commandBuffer->needNewVertexUniformOffsets = true;
- commandBuffer->needNewFragmentResourceDescriptorSet = true;
- commandBuffer->needNewFragmentUniformDescriptorSet = true;
- commandBuffer->needNewFragmentUniformOffsets = true;
- commandBuffer->needNewComputeReadOnlyDescriptorSet = true;
- commandBuffer->needNewComputeUniformDescriptorSet = true;
- commandBuffer->needNewComputeUniformOffsets = true;
- commandBuffer->vertexResourceDescriptorSet = VK_NULL_HANDLE;
- commandBuffer->vertexUniformDescriptorSet = VK_NULL_HANDLE;
- commandBuffer->fragmentResourceDescriptorSet = VK_NULL_HANDLE;
- commandBuffer->fragmentUniformDescriptorSet = VK_NULL_HANDLE;
- commandBuffer->computeReadOnlyDescriptorSet = VK_NULL_HANDLE;
- commandBuffer->computeReadWriteDescriptorSet = VK_NULL_HANDLE;
- commandBuffer->computeUniformDescriptorSet = VK_NULL_HANDLE;
- SDL_zeroa(commandBuffer->vertexBuffers);
- SDL_zeroa(commandBuffer->vertexBufferOffsets);
- commandBuffer->vertexBufferCount = 0;
- SDL_zeroa(commandBuffer->vertexSamplerTextureViewBindings);
- SDL_zeroa(commandBuffer->vertexSamplerBindings);
- SDL_zeroa(commandBuffer->vertexStorageTextureViewBindings);
- SDL_zeroa(commandBuffer->vertexStorageBufferBindings);
- SDL_zeroa(commandBuffer->fragmentSamplerTextureViewBindings);
- SDL_zeroa(commandBuffer->fragmentSamplerBindings);
- SDL_zeroa(commandBuffer->fragmentStorageTextureViewBindings);
- SDL_zeroa(commandBuffer->fragmentStorageBufferBindings);
- SDL_zeroa(commandBuffer->readWriteComputeStorageTextureSubresources);
- commandBuffer->readWriteComputeStorageTextureSubresourceCount = 0;
- SDL_zeroa(commandBuffer->readWriteComputeStorageBuffers);
- SDL_zeroa(commandBuffer->computeSamplerTextureViewBindings);
- SDL_zeroa(commandBuffer->computeSamplerBindings);
- SDL_zeroa(commandBuffer->readOnlyComputeStorageTextureViewBindings);
- SDL_zeroa(commandBuffer->readOnlyComputeStorageBufferBindings);
- SDL_zeroa(commandBuffer->readOnlyComputeStorageTextures);
- SDL_zeroa(commandBuffer->readOnlyComputeStorageBuffers);
- commandBuffer->autoReleaseFence = true;
- commandBuffer->swapchainRequested = false;
- commandBuffer->isDefrag = 0;
- /* Reset the command buffer here to avoid resets being called
- * from a separate thread than where the command buffer was acquired
- */
- result = renderer->vkResetCommandBuffer(
- commandBuffer->commandBuffer,
- VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
- CHECK_VULKAN_ERROR_AND_RETURN(result, vkResetCommandBuffer, NULL);
- if (!VULKAN_INTERNAL_BeginCommandBuffer(renderer, commandBuffer)) {
- return NULL;
- }
- return (SDL_GPUCommandBuffer *)commandBuffer;
- }
- static bool VULKAN_QueryFence(
- SDL_GPURenderer *driverData,
- SDL_GPUFence *fence)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- VkResult result;
- result = renderer->vkGetFenceStatus(
- renderer->logicalDevice,
- ((VulkanFenceHandle *)fence)->fence);
- if (result == VK_SUCCESS) {
- return true;
- } else if (result == VK_NOT_READY) {
- return false;
- } else {
- SET_ERROR_AND_RETURN("vkGetFenceStatus: %s", VkErrorMessages(result), false);
- }
- }
- static void VULKAN_INTERNAL_ReturnFenceToPool(
- VulkanRenderer *renderer,
- VulkanFenceHandle *fenceHandle)
- {
- SDL_LockMutex(renderer->fencePool.lock);
- EXPAND_ARRAY_IF_NEEDED(
- renderer->fencePool.availableFences,
- VulkanFenceHandle *,
- renderer->fencePool.availableFenceCount + 1,
- renderer->fencePool.availableFenceCapacity,
- renderer->fencePool.availableFenceCapacity * 2);
- renderer->fencePool.availableFences[renderer->fencePool.availableFenceCount] = fenceHandle;
- renderer->fencePool.availableFenceCount += 1;
- SDL_UnlockMutex(renderer->fencePool.lock);
- }
- static void VULKAN_ReleaseFence(
- SDL_GPURenderer *driverData,
- SDL_GPUFence *fence)
- {
- VulkanFenceHandle *handle = (VulkanFenceHandle *)fence;
- if (SDL_AtomicDecRef(&handle->referenceCount)) {
- VULKAN_INTERNAL_ReturnFenceToPool((VulkanRenderer *)driverData, handle);
- }
- }
- static WindowData *VULKAN_INTERNAL_FetchWindowData(
- SDL_Window *window)
- {
- SDL_PropertiesID properties = SDL_GetWindowProperties(window);
- return (WindowData *)SDL_GetPointerProperty(properties, WINDOW_PROPERTY_DATA, NULL);
- }
- static bool VULKAN_INTERNAL_OnWindowResize(void *userdata, SDL_Event *e)
- {
- SDL_Window *w = (SDL_Window *)userdata;
- WindowData *data;
- if (e->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED && e->window.windowID == SDL_GetWindowID(w)) {
- data = VULKAN_INTERNAL_FetchWindowData(w);
- data->needsSwapchainRecreate = true;
- data->swapchainCreateWidth = e->window.data1;
- data->swapchainCreateHeight = e->window.data2;
- }
- return true;
- }
- static bool VULKAN_SupportsSwapchainComposition(
- SDL_GPURenderer *driverData,
- SDL_Window *window,
- SDL_GPUSwapchainComposition swapchainComposition)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window);
- VkSurfaceKHR surface;
- SwapchainSupportDetails supportDetails;
- bool result = false;
- if (windowData == NULL) {
- SET_STRING_ERROR_AND_RETURN("Must claim window before querying swapchain composition support!", false);
- }
- surface = windowData->surface;
- if (!surface) {
- SET_STRING_ERROR_AND_RETURN("Window has no Vulkan surface", false);
- }
- if (VULKAN_INTERNAL_QuerySwapchainSupport(
- renderer,
- renderer->physicalDevice,
- surface,
- &supportDetails)) {
- result = VULKAN_INTERNAL_VerifySwapSurfaceFormat(
- SwapchainCompositionToFormat[swapchainComposition],
- SwapchainCompositionToColorSpace[swapchainComposition],
- supportDetails.formats,
- supportDetails.formatsLength);
- if (!result) {
- // Let's try again with the fallback format...
- result = VULKAN_INTERNAL_VerifySwapSurfaceFormat(
- SwapchainCompositionToFallbackFormat[swapchainComposition],
- SwapchainCompositionToColorSpace[swapchainComposition],
- supportDetails.formats,
- supportDetails.formatsLength);
- }
- SDL_free(supportDetails.formats);
- SDL_free(supportDetails.presentModes);
- }
- return result;
- }
- static bool VULKAN_SupportsPresentMode(
- SDL_GPURenderer *driverData,
- SDL_Window *window,
- SDL_GPUPresentMode presentMode)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window);
- VkSurfaceKHR surface;
- SwapchainSupportDetails supportDetails;
- bool result = false;
- if (windowData == NULL) {
- SET_STRING_ERROR_AND_RETURN("Must claim window before querying present mode support!", false);
- }
- surface = windowData->surface;
- if (!surface) {
- SET_STRING_ERROR_AND_RETURN("Window has no Vulkan surface", false);
- }
- if (VULKAN_INTERNAL_QuerySwapchainSupport(
- renderer,
- renderer->physicalDevice,
- surface,
- &supportDetails)) {
- result = VULKAN_INTERNAL_VerifySwapPresentMode(
- SDLToVK_PresentMode[presentMode],
- supportDetails.presentModes,
- supportDetails.presentModesLength);
- SDL_free(supportDetails.formats);
- SDL_free(supportDetails.presentModes);
- }
- return result;
- }
- static bool VULKAN_ClaimWindow(
- SDL_GPURenderer *driverData,
- SDL_Window *window)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window);
- if (windowData == NULL) {
- windowData = SDL_calloc(1, sizeof(WindowData));
- windowData->window = window;
- windowData->presentMode = SDL_GPU_PRESENTMODE_VSYNC;
- windowData->swapchainComposition = SDL_GPU_SWAPCHAINCOMPOSITION_SDR;
- // On non-Apple platforms the swapchain capability currentExtent can be different from the window,
- // so we have to query the window size.
- #ifndef SDL_PLATFORM_APPLE
- int w, h;
- SDL_SyncWindow(window);
- SDL_GetWindowSizeInPixels(window, &w, &h);
- windowData->swapchainCreateWidth = w;
- windowData->swapchainCreateHeight = h;
- #endif
- SDL_VideoDevice *videoDevice = SDL_GetVideoDevice();
- if (!videoDevice)
- {
- SDL_SetError("No video device found!");
- SDL_free(windowData);
- return false;
- }
- if (!videoDevice->Vulkan_CreateSurface)
- {
- SDL_SetError("Video device does not have Vulkan_CreateSurface implemented!");
- SDL_free(windowData);
- return false;
- }
- // Each window must have its own surface.
- if (!videoDevice->Vulkan_CreateSurface(
- videoDevice,
- windowData->window,
- renderer->instance,
- NULL, // FIXME: VAllocationCallbacks
- &windowData->surface)) {
- SDL_SetError("Failed to create Vulkan surface!");
- SDL_free(windowData);
- return false;
- }
- Uint32 createSwapchainResult = VULKAN_INTERNAL_CreateSwapchain(renderer, windowData);
- if (createSwapchainResult == 1) {
- SDL_SetPointerProperty(SDL_GetWindowProperties(window), WINDOW_PROPERTY_DATA, windowData);
- SDL_LockMutex(renderer->windowLock);
- if (renderer->claimedWindowCount >= renderer->claimedWindowCapacity) {
- renderer->claimedWindowCapacity *= 2;
- renderer->claimedWindows = SDL_realloc(
- renderer->claimedWindows,
- renderer->claimedWindowCapacity * sizeof(WindowData *));
- }
- renderer->claimedWindows[renderer->claimedWindowCount] = windowData;
- renderer->claimedWindowCount += 1;
- SDL_UnlockMutex(renderer->windowLock);
- SDL_AddWindowEventWatch(SDL_WINDOW_EVENT_WATCH_NORMAL, VULKAN_INTERNAL_OnWindowResize, window);
- return true;
- } else if (createSwapchainResult == VULKAN_INTERNAL_TRY_AGAIN) {
- windowData->needsSwapchainRecreate = true;
- return true;
- } else {
- // Failed to create swapchain, destroy surface and free data
- renderer->vkDestroySurfaceKHR(
- renderer->instance,
- windowData->surface,
- NULL);
- SDL_free(windowData);
- return false;
- }
- } else {
- SET_STRING_ERROR_AND_RETURN("Window already claimed!", false);
- }
- }
- static void VULKAN_ReleaseWindow(
- SDL_GPURenderer *driverData,
- SDL_Window *window)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window);
- Uint32 i;
- if (windowData == NULL) {
- return;
- }
- VULKAN_Wait(driverData);
- for (i = 0; i < MAX_FRAMES_IN_FLIGHT; i += 1) {
- if (windowData->inFlightFences[i] != NULL) {
- VULKAN_ReleaseFence(
- driverData,
- windowData->inFlightFences[i]);
- }
- }
- VULKAN_INTERNAL_DestroySwapchain(
- (VulkanRenderer *)driverData,
- windowData);
- renderer->vkDestroySurfaceKHR(
- renderer->instance,
- windowData->surface,
- NULL);
- windowData->surface = VK_NULL_HANDLE;
- SDL_LockMutex(renderer->windowLock);
- for (i = 0; i < renderer->claimedWindowCount; i += 1) {
- if (renderer->claimedWindows[i]->window == window) {
- renderer->claimedWindows[i] = renderer->claimedWindows[renderer->claimedWindowCount - 1];
- renderer->claimedWindowCount -= 1;
- break;
- }
- }
- SDL_UnlockMutex(renderer->windowLock);
- SDL_free(windowData);
- SDL_ClearProperty(SDL_GetWindowProperties(window), WINDOW_PROPERTY_DATA);
- SDL_RemoveWindowEventWatch(SDL_WINDOW_EVENT_WATCH_NORMAL, VULKAN_INTERNAL_OnWindowResize, window);
- }
- static Uint32 VULKAN_INTERNAL_RecreateSwapchain(
- VulkanRenderer *renderer,
- WindowData *windowData)
- {
- Uint32 i;
- if (!VULKAN_Wait((SDL_GPURenderer *)renderer)) {
- return false;
- }
- for (i = 0; i < MAX_FRAMES_IN_FLIGHT; i += 1) {
- if (windowData->inFlightFences[i] != NULL) {
- VULKAN_ReleaseFence(
- (SDL_GPURenderer *)renderer,
- windowData->inFlightFences[i]);
- windowData->inFlightFences[i] = NULL;
- }
- }
- #ifdef SDL_VIDEO_DRIVER_PRIVATE
- // Private platforms also invalidate the window, so don't try to preserve the surface/swapchain
- VULKAN_INTERNAL_DestroySwapchain(renderer, windowData);
- #else
- VULKAN_INTERNAL_DestroySwapchainImage(renderer, windowData);
- #endif
- return VULKAN_INTERNAL_CreateSwapchain(renderer, windowData);
- }
- static bool VULKAN_WaitForSwapchain(
- SDL_GPURenderer *driverData,
- SDL_Window *window)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window);
- if (windowData == NULL) {
- SET_STRING_ERROR_AND_RETURN("Cannot wait for a swapchain from an unclaimed window!", false);
- }
- if (windowData->inFlightFences[windowData->frameCounter] != NULL) {
- if (!VULKAN_WaitForFences(
- driverData,
- true,
- &windowData->inFlightFences[windowData->frameCounter],
- 1)) {
- return false;
- }
- }
- return true;
- }
- static bool VULKAN_INTERNAL_AcquireSwapchainTexture(
- bool block,
- SDL_GPUCommandBuffer *commandBuffer,
- SDL_Window *window,
- SDL_GPUTexture **swapchainTexture,
- Uint32 *swapchainTextureWidth,
- Uint32 *swapchainTextureHeight)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- Uint32 swapchainImageIndex;
- WindowData *windowData;
- VkResult acquireResult = VK_SUCCESS;
- VulkanTextureContainer *swapchainTextureContainer = NULL;
- VulkanPresentData *presentData;
- *swapchainTexture = NULL;
- if (swapchainTextureWidth) {
- *swapchainTextureWidth = 0;
- }
- if (swapchainTextureHeight) {
- *swapchainTextureHeight = 0;
- }
- windowData = VULKAN_INTERNAL_FetchWindowData(window);
- if (windowData == NULL) {
- SET_STRING_ERROR_AND_RETURN("Cannot acquire a swapchain texture from an unclaimed window!", false);
- }
- // The command buffer is flagged for cleanup when the swapchain is requested as a cleanup timing mechanism
- vulkanCommandBuffer->swapchainRequested = true;
- if (window->flags & SDL_WINDOW_HIDDEN) {
- // Edge case, texture is filled in with NULL but not an error
- return true;
- }
- if (windowData->needsSurfaceRecreate) {
- SDL_VideoDevice *videoDevice = SDL_GetVideoDevice();
- SDL_assert(videoDevice);
- SDL_assert(videoDevice->Vulkan_CreateSurface);
- renderer->vkDestroySurfaceKHR(
- renderer->instance,
- windowData->surface,
- NULL);
- if (!videoDevice->Vulkan_CreateSurface(
- videoDevice,
- windowData->window,
- renderer->instance,
- NULL, // FIXME: VAllocationCallbacks
- &windowData->surface)) {
- SET_STRING_ERROR_AND_RETURN("Failed to recreate Vulkan surface!", false);
- }
- }
- // If window data marked as needing swapchain recreate, try to recreate
- if (windowData->needsSwapchainRecreate) {
- Uint32 recreateSwapchainResult = VULKAN_INTERNAL_RecreateSwapchain(renderer, windowData);
- if (!recreateSwapchainResult) {
- return false;
- } else if (recreateSwapchainResult == VULKAN_INTERNAL_TRY_AGAIN) {
- // Edge case, texture is filled in with NULL but not an error
- if (windowData->inFlightFences[windowData->frameCounter] != NULL) {
- VULKAN_ReleaseFence(
- (SDL_GPURenderer *)renderer,
- windowData->inFlightFences[windowData->frameCounter]);
- windowData->inFlightFences[windowData->frameCounter] = NULL;
- }
- return true;
- }
- // Unset this flag until after the swapchain has been recreated to let VULKAN_INTERNAL_CreateSwapchain()
- // know whether it needs to pass the old swapchain or not.
- windowData->needsSurfaceRecreate = false;
- }
- if (windowData->inFlightFences[windowData->frameCounter] != NULL) {
- if (block) {
- // If we are blocking, just wait for the fence!
- if (!VULKAN_WaitForFences(
- (SDL_GPURenderer *)renderer,
- true,
- &windowData->inFlightFences[windowData->frameCounter],
- 1)) {
- return false;
- }
- } else {
- // If we are not blocking and the least recent fence is not signaled,
- // return true to indicate that there is no error but rendering should be skipped.
- if (!VULKAN_QueryFence(
- (SDL_GPURenderer *)renderer,
- windowData->inFlightFences[windowData->frameCounter])) {
- return true;
- }
- }
- VULKAN_ReleaseFence(
- (SDL_GPURenderer *)renderer,
- windowData->inFlightFences[windowData->frameCounter]);
- windowData->inFlightFences[windowData->frameCounter] = NULL;
- }
- // Finally, try to acquire!
- while (true) {
- acquireResult = renderer->vkAcquireNextImageKHR(
- renderer->logicalDevice,
- windowData->swapchain,
- SDL_MAX_UINT64,
- windowData->imageAvailableSemaphore[windowData->frameCounter],
- VK_NULL_HANDLE,
- &swapchainImageIndex);
- if (acquireResult == VK_SUCCESS || acquireResult == VK_SUBOPTIMAL_KHR) {
- break; // we got the next image!
- }
- // If acquisition is invalid, let's try to recreate
- Uint32 recreateSwapchainResult = VULKAN_INTERNAL_RecreateSwapchain(renderer, windowData);
- if (!recreateSwapchainResult) {
- return false;
- } else if (recreateSwapchainResult == VULKAN_INTERNAL_TRY_AGAIN) {
- // Edge case, texture is filled in with NULL but not an error
- return true;
- }
- }
- if (swapchainTextureWidth) {
- *swapchainTextureWidth = windowData->width;
- }
- if (swapchainTextureHeight) {
- *swapchainTextureHeight = windowData->height;
- }
- swapchainTextureContainer = &windowData->textureContainers[swapchainImageIndex];
- // We need a special execution dependency with pWaitDstStageMask or image transition can start before acquire finishes
- VkImageMemoryBarrier imageBarrier;
- imageBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- imageBarrier.pNext = NULL;
- imageBarrier.srcAccessMask = 0;
- imageBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
- imageBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- imageBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- imageBarrier.image = swapchainTextureContainer->activeTexture->image;
- imageBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- imageBarrier.subresourceRange.baseMipLevel = 0;
- imageBarrier.subresourceRange.levelCount = 1;
- imageBarrier.subresourceRange.baseArrayLayer = 0;
- imageBarrier.subresourceRange.layerCount = 1;
- renderer->vkCmdPipelineBarrier(
- vulkanCommandBuffer->commandBuffer,
- VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
- VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
- 0,
- 0,
- NULL,
- 0,
- NULL,
- 1,
- &imageBarrier);
- // Set up present struct
- if (vulkanCommandBuffer->presentDataCount == vulkanCommandBuffer->presentDataCapacity) {
- vulkanCommandBuffer->presentDataCapacity += 1;
- vulkanCommandBuffer->presentDatas = SDL_realloc(
- vulkanCommandBuffer->presentDatas,
- vulkanCommandBuffer->presentDataCapacity * sizeof(VulkanPresentData));
- }
- presentData = &vulkanCommandBuffer->presentDatas[vulkanCommandBuffer->presentDataCount];
- vulkanCommandBuffer->presentDataCount += 1;
- presentData->windowData = windowData;
- presentData->swapchainImageIndex = swapchainImageIndex;
- // Set up present semaphores
- if (vulkanCommandBuffer->waitSemaphoreCount == vulkanCommandBuffer->waitSemaphoreCapacity) {
- vulkanCommandBuffer->waitSemaphoreCapacity += 1;
- vulkanCommandBuffer->waitSemaphores = SDL_realloc(
- vulkanCommandBuffer->waitSemaphores,
- vulkanCommandBuffer->waitSemaphoreCapacity * sizeof(VkSemaphore));
- }
- vulkanCommandBuffer->waitSemaphores[vulkanCommandBuffer->waitSemaphoreCount] =
- windowData->imageAvailableSemaphore[windowData->frameCounter];
- vulkanCommandBuffer->waitSemaphoreCount += 1;
- if (vulkanCommandBuffer->signalSemaphoreCount == vulkanCommandBuffer->signalSemaphoreCapacity) {
- vulkanCommandBuffer->signalSemaphoreCapacity += 1;
- vulkanCommandBuffer->signalSemaphores = SDL_realloc(
- vulkanCommandBuffer->signalSemaphores,
- vulkanCommandBuffer->signalSemaphoreCapacity * sizeof(VkSemaphore));
- }
- vulkanCommandBuffer->signalSemaphores[vulkanCommandBuffer->signalSemaphoreCount] =
- windowData->renderFinishedSemaphore[swapchainImageIndex];
- vulkanCommandBuffer->signalSemaphoreCount += 1;
- *swapchainTexture = (SDL_GPUTexture *)swapchainTextureContainer;
- return true;
- }
- static bool VULKAN_AcquireSwapchainTexture(
- SDL_GPUCommandBuffer *command_buffer,
- SDL_Window *window,
- SDL_GPUTexture **swapchain_texture,
- Uint32 *swapchain_texture_width,
- Uint32 *swapchain_texture_height
- ) {
- return VULKAN_INTERNAL_AcquireSwapchainTexture(
- false,
- command_buffer,
- window,
- swapchain_texture,
- swapchain_texture_width,
- swapchain_texture_height);
- }
- static bool VULKAN_WaitAndAcquireSwapchainTexture(
- SDL_GPUCommandBuffer *command_buffer,
- SDL_Window *window,
- SDL_GPUTexture **swapchain_texture,
- Uint32 *swapchain_texture_width,
- Uint32 *swapchain_texture_height
- ) {
- return VULKAN_INTERNAL_AcquireSwapchainTexture(
- true,
- command_buffer,
- window,
- swapchain_texture,
- swapchain_texture_width,
- swapchain_texture_height);
- }
- static SDL_GPUTextureFormat VULKAN_GetSwapchainTextureFormat(
- SDL_GPURenderer *driverData,
- SDL_Window *window)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window);
- if (windowData == NULL) {
- SET_STRING_ERROR_AND_RETURN("Cannot get swapchain format, window has not been claimed!", SDL_GPU_TEXTUREFORMAT_INVALID);
- }
- return SwapchainCompositionToSDLFormat(
- windowData->swapchainComposition,
- windowData->usingFallbackFormat);
- }
- static bool VULKAN_SetSwapchainParameters(
- SDL_GPURenderer *driverData,
- SDL_Window *window,
- SDL_GPUSwapchainComposition swapchainComposition,
- SDL_GPUPresentMode presentMode)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window);
- if (windowData == NULL) {
- SET_STRING_ERROR_AND_RETURN("Cannot set swapchain parameters on unclaimed window!", false);
- }
- if (!VULKAN_SupportsSwapchainComposition(driverData, window, swapchainComposition)) {
- SET_STRING_ERROR_AND_RETURN("Swapchain composition not supported!", false);
- }
- if (!VULKAN_SupportsPresentMode(driverData, window, presentMode)) {
- SET_STRING_ERROR_AND_RETURN("Present mode not supported!", false);
- }
- windowData->presentMode = presentMode;
- windowData->swapchainComposition = swapchainComposition;
- Uint32 recreateSwapchainResult = VULKAN_INTERNAL_RecreateSwapchain(renderer, windowData);
- if (!recreateSwapchainResult) {
- return false;
- } else if (recreateSwapchainResult == VULKAN_INTERNAL_TRY_AGAIN) {
- // Edge case, swapchain extent is (0, 0) but this is not an error
- windowData->needsSwapchainRecreate = true;
- return true;
- }
- return true;
- }
- static bool VULKAN_SetAllowedFramesInFlight(
- SDL_GPURenderer *driverData,
- Uint32 allowedFramesInFlight)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- renderer->allowedFramesInFlight = allowedFramesInFlight;
- for (Uint32 i = 0; i < renderer->claimedWindowCount; i += 1) {
- WindowData *windowData = renderer->claimedWindows[i];
- Uint32 recreateResult = VULKAN_INTERNAL_RecreateSwapchain(renderer, windowData);
- if (!recreateResult) {
- return false;
- } else if (recreateResult == VULKAN_INTERNAL_TRY_AGAIN) {
- // Edge case, swapchain extent is (0, 0) but this is not an error
- windowData->needsSwapchainRecreate = true;
- }
- }
- return true;
- }
- // Submission structure
- static VulkanFenceHandle *VULKAN_INTERNAL_AcquireFenceFromPool(
- VulkanRenderer *renderer)
- {
- VulkanFenceHandle *handle;
- VkFenceCreateInfo fenceCreateInfo;
- VkFence fence;
- VkResult vulkanResult;
- if (renderer->fencePool.availableFenceCount == 0) {
- // Create fence
- fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
- fenceCreateInfo.pNext = NULL;
- fenceCreateInfo.flags = 0;
- vulkanResult = renderer->vkCreateFence(
- renderer->logicalDevice,
- &fenceCreateInfo,
- NULL,
- &fence);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateFence, NULL);
- handle = SDL_malloc(sizeof(VulkanFenceHandle));
- handle->fence = fence;
- SDL_SetAtomicInt(&handle->referenceCount, 0);
- return handle;
- }
- SDL_LockMutex(renderer->fencePool.lock);
- handle = renderer->fencePool.availableFences[renderer->fencePool.availableFenceCount - 1];
- renderer->fencePool.availableFenceCount -= 1;
- vulkanResult = renderer->vkResetFences(
- renderer->logicalDevice,
- 1,
- &handle->fence);
- SDL_UnlockMutex(renderer->fencePool.lock);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkResetFences, NULL);
- return handle;
- }
- static void VULKAN_INTERNAL_PerformPendingDestroys(
- VulkanRenderer *renderer)
- {
- SDL_LockMutex(renderer->disposeLock);
- for (Sint32 i = renderer->texturesToDestroyCount - 1; i >= 0; i -= 1) {
- if (SDL_GetAtomicInt(&renderer->texturesToDestroy[i]->referenceCount) == 0) {
- VULKAN_INTERNAL_DestroyTexture(
- renderer,
- renderer->texturesToDestroy[i]);
- renderer->texturesToDestroy[i] = renderer->texturesToDestroy[renderer->texturesToDestroyCount - 1];
- renderer->texturesToDestroyCount -= 1;
- }
- }
- for (Sint32 i = renderer->buffersToDestroyCount - 1; i >= 0; i -= 1) {
- if (SDL_GetAtomicInt(&renderer->buffersToDestroy[i]->referenceCount) == 0) {
- VULKAN_INTERNAL_DestroyBuffer(
- renderer,
- renderer->buffersToDestroy[i]);
- renderer->buffersToDestroy[i] = renderer->buffersToDestroy[renderer->buffersToDestroyCount - 1];
- renderer->buffersToDestroyCount -= 1;
- }
- }
- for (Sint32 i = renderer->graphicsPipelinesToDestroyCount - 1; i >= 0; i -= 1) {
- if (SDL_GetAtomicInt(&renderer->graphicsPipelinesToDestroy[i]->referenceCount) == 0) {
- VULKAN_INTERNAL_DestroyGraphicsPipeline(
- renderer,
- renderer->graphicsPipelinesToDestroy[i]);
- renderer->graphicsPipelinesToDestroy[i] = renderer->graphicsPipelinesToDestroy[renderer->graphicsPipelinesToDestroyCount - 1];
- renderer->graphicsPipelinesToDestroyCount -= 1;
- }
- }
- for (Sint32 i = renderer->computePipelinesToDestroyCount - 1; i >= 0; i -= 1) {
- if (SDL_GetAtomicInt(&renderer->computePipelinesToDestroy[i]->referenceCount) == 0) {
- VULKAN_INTERNAL_DestroyComputePipeline(
- renderer,
- renderer->computePipelinesToDestroy[i]);
- renderer->computePipelinesToDestroy[i] = renderer->computePipelinesToDestroy[renderer->computePipelinesToDestroyCount - 1];
- renderer->computePipelinesToDestroyCount -= 1;
- }
- }
- for (Sint32 i = renderer->shadersToDestroyCount - 1; i >= 0; i -= 1) {
- if (SDL_GetAtomicInt(&renderer->shadersToDestroy[i]->referenceCount) == 0) {
- VULKAN_INTERNAL_DestroyShader(
- renderer,
- renderer->shadersToDestroy[i]);
- renderer->shadersToDestroy[i] = renderer->shadersToDestroy[renderer->shadersToDestroyCount - 1];
- renderer->shadersToDestroyCount -= 1;
- }
- }
- for (Sint32 i = renderer->samplersToDestroyCount - 1; i >= 0; i -= 1) {
- if (SDL_GetAtomicInt(&renderer->samplersToDestroy[i]->referenceCount) == 0) {
- VULKAN_INTERNAL_DestroySampler(
- renderer,
- renderer->samplersToDestroy[i]);
- renderer->samplersToDestroy[i] = renderer->samplersToDestroy[renderer->samplersToDestroyCount - 1];
- renderer->samplersToDestroyCount -= 1;
- }
- }
- for (Sint32 i = renderer->framebuffersToDestroyCount - 1; i >= 0; i -= 1) {
- if (SDL_GetAtomicInt(&renderer->framebuffersToDestroy[i]->referenceCount) == 0) {
- VULKAN_INTERNAL_DestroyFramebuffer(
- renderer,
- renderer->framebuffersToDestroy[i]);
- renderer->framebuffersToDestroy[i] = renderer->framebuffersToDestroy[renderer->framebuffersToDestroyCount - 1];
- renderer->framebuffersToDestroyCount -= 1;
- }
- }
- SDL_UnlockMutex(renderer->disposeLock);
- }
- static void VULKAN_INTERNAL_CleanCommandBuffer(
- VulkanRenderer *renderer,
- VulkanCommandBuffer *commandBuffer,
- bool cancel)
- {
- if (commandBuffer->autoReleaseFence) {
- VULKAN_ReleaseFence(
- (SDL_GPURenderer *)renderer,
- (SDL_GPUFence *)commandBuffer->inFlightFence);
- commandBuffer->inFlightFence = NULL;
- }
- // Uniform buffers are now available
- SDL_LockMutex(renderer->acquireUniformBufferLock);
- for (Sint32 i = 0; i < commandBuffer->usedUniformBufferCount; i += 1) {
- VULKAN_INTERNAL_ReturnUniformBufferToPool(
- renderer,
- commandBuffer->usedUniformBuffers[i]);
- }
- commandBuffer->usedUniformBufferCount = 0;
- SDL_UnlockMutex(renderer->acquireUniformBufferLock);
- // Decrement reference counts
- for (Sint32 i = 0; i < commandBuffer->usedBufferCount; i += 1) {
- (void)SDL_AtomicDecRef(&commandBuffer->usedBuffers[i]->referenceCount);
- }
- commandBuffer->usedBufferCount = 0;
- for (Sint32 i = 0; i < commandBuffer->usedTextureCount; i += 1) {
- (void)SDL_AtomicDecRef(&commandBuffer->usedTextures[i]->referenceCount);
- }
- commandBuffer->usedTextureCount = 0;
- for (Sint32 i = 0; i < commandBuffer->usedSamplerCount; i += 1) {
- (void)SDL_AtomicDecRef(&commandBuffer->usedSamplers[i]->referenceCount);
- }
- commandBuffer->usedSamplerCount = 0;
- for (Sint32 i = 0; i < commandBuffer->usedGraphicsPipelineCount; i += 1) {
- (void)SDL_AtomicDecRef(&commandBuffer->usedGraphicsPipelines[i]->referenceCount);
- }
- commandBuffer->usedGraphicsPipelineCount = 0;
- for (Sint32 i = 0; i < commandBuffer->usedComputePipelineCount; i += 1) {
- (void)SDL_AtomicDecRef(&commandBuffer->usedComputePipelines[i]->referenceCount);
- }
- commandBuffer->usedComputePipelineCount = 0;
- for (Sint32 i = 0; i < commandBuffer->usedFramebufferCount; i += 1) {
- (void)SDL_AtomicDecRef(&commandBuffer->usedFramebuffers[i]->referenceCount);
- }
- commandBuffer->usedFramebufferCount = 0;
- // Reset presentation data
- commandBuffer->presentDataCount = 0;
- commandBuffer->waitSemaphoreCount = 0;
- commandBuffer->signalSemaphoreCount = 0;
- commandBuffer->swapchainRequested = false;
- // Reset defrag state
- if (commandBuffer->isDefrag) {
- renderer->defragInProgress = 0;
- }
- // Return command buffer to pool
- SDL_LockMutex(renderer->acquireCommandBufferLock);
- if (commandBuffer->commandPool->inactiveCommandBufferCount == commandBuffer->commandPool->inactiveCommandBufferCapacity) {
- commandBuffer->commandPool->inactiveCommandBufferCapacity += 1;
- commandBuffer->commandPool->inactiveCommandBuffers = SDL_realloc(
- commandBuffer->commandPool->inactiveCommandBuffers,
- commandBuffer->commandPool->inactiveCommandBufferCapacity * sizeof(VulkanCommandBuffer *));
- }
- commandBuffer->commandPool->inactiveCommandBuffers[commandBuffer->commandPool->inactiveCommandBufferCount] = commandBuffer;
- commandBuffer->commandPool->inactiveCommandBufferCount += 1;
- // Release descriptor set cache
- VULKAN_INTERNAL_ReturnDescriptorSetCacheToPool(
- renderer,
- commandBuffer->descriptorSetCache);
- commandBuffer->descriptorSetCache = NULL;
- SDL_UnlockMutex(renderer->acquireCommandBufferLock);
- // Remove this command buffer from the submitted list
- if (!cancel) {
- for (Uint32 i = 0; i < renderer->submittedCommandBufferCount; i += 1) {
- if (renderer->submittedCommandBuffers[i] == commandBuffer) {
- renderer->submittedCommandBuffers[i] = renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount - 1];
- renderer->submittedCommandBufferCount -= 1;
- }
- }
- }
- }
- static bool VULKAN_WaitForFences(
- SDL_GPURenderer *driverData,
- bool waitAll,
- SDL_GPUFence *const *fences,
- Uint32 numFences)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- VkFence *vkFences = SDL_stack_alloc(VkFence, numFences);
- VkResult result;
- for (Uint32 i = 0; i < numFences; i += 1) {
- vkFences[i] = ((VulkanFenceHandle *)fences[i])->fence;
- }
- result = renderer->vkWaitForFences(
- renderer->logicalDevice,
- numFences,
- vkFences,
- waitAll,
- SDL_MAX_UINT64);
- CHECK_VULKAN_ERROR_AND_RETURN(result, vkWaitForFences, false);
- SDL_stack_free(vkFences);
- SDL_LockMutex(renderer->submitLock);
- for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) {
- result = renderer->vkGetFenceStatus(
- renderer->logicalDevice,
- renderer->submittedCommandBuffers[i]->inFlightFence->fence);
- if (result == VK_SUCCESS) {
- VULKAN_INTERNAL_CleanCommandBuffer(
- renderer,
- renderer->submittedCommandBuffers[i],
- false);
- }
- }
- VULKAN_INTERNAL_PerformPendingDestroys(renderer);
- SDL_UnlockMutex(renderer->submitLock);
- return true;
- }
- static bool VULKAN_Wait(
- SDL_GPURenderer *driverData)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- VulkanCommandBuffer *commandBuffer;
- VkResult result;
- Sint32 i;
- SDL_LockMutex(renderer->submitLock);
- result = renderer->vkDeviceWaitIdle(renderer->logicalDevice);
- if (result != VK_SUCCESS) {
- if (renderer->debugMode) {
- SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s %s", "vkDeviceWaitIdle", VkErrorMessages(result));
- }
- SDL_SetError("%s %s", "vkDeviceWaitIdle", VkErrorMessages(result));
- SDL_UnlockMutex(renderer->submitLock);
- return false;
- }
- for (i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) {
- commandBuffer = renderer->submittedCommandBuffers[i];
- VULKAN_INTERNAL_CleanCommandBuffer(renderer, commandBuffer, false);
- }
- VULKAN_INTERNAL_PerformPendingDestroys(renderer);
- SDL_UnlockMutex(renderer->submitLock);
- return true;
- }
- static SDL_GPUFence *VULKAN_SubmitAndAcquireFence(
- SDL_GPUCommandBuffer *commandBuffer)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- vulkanCommandBuffer->autoReleaseFence = false;
- if (!VULKAN_Submit(commandBuffer)) {
- return NULL;
- }
- return (SDL_GPUFence *)vulkanCommandBuffer->inFlightFence;
- }
- static void VULKAN_INTERNAL_ReleaseCommandBuffer(VulkanCommandBuffer *vulkanCommandBuffer)
- {
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- if (renderer->submittedCommandBufferCount + 1 >= renderer->submittedCommandBufferCapacity) {
- renderer->submittedCommandBufferCapacity = renderer->submittedCommandBufferCount + 1;
- renderer->submittedCommandBuffers = SDL_realloc(
- renderer->submittedCommandBuffers,
- sizeof(VulkanCommandBuffer *) * renderer->submittedCommandBufferCapacity);
- }
- renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount] = vulkanCommandBuffer;
- renderer->submittedCommandBufferCount += 1;
- }
- static bool VULKAN_Submit(
- SDL_GPUCommandBuffer *commandBuffer)
- {
- VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- VulkanRenderer *renderer = vulkanCommandBuffer->renderer;
- VkSubmitInfo submitInfo;
- VkPresentInfoKHR presentInfo;
- VulkanPresentData *presentData;
- VkResult vulkanResult, presentResult = VK_SUCCESS;
- VkPipelineStageFlags waitStages[MAX_PRESENT_COUNT];
- Uint32 swapchainImageIndex;
- VulkanTextureSubresource *swapchainTextureSubresource;
- VulkanMemorySubAllocator *allocator;
- bool performCleanups =
- (renderer->claimedWindowCount > 0 && vulkanCommandBuffer->swapchainRequested) ||
- renderer->claimedWindowCount == 0;
- SDL_LockMutex(renderer->submitLock);
- // FIXME: Can this just be permanent?
- for (Uint32 i = 0; i < MAX_PRESENT_COUNT; i += 1) {
- waitStages[i] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- }
- for (Uint32 j = 0; j < vulkanCommandBuffer->presentDataCount; j += 1) {
- swapchainImageIndex = vulkanCommandBuffer->presentDatas[j].swapchainImageIndex;
- swapchainTextureSubresource = VULKAN_INTERNAL_FetchTextureSubresource(
- &vulkanCommandBuffer->presentDatas[j].windowData->textureContainers[swapchainImageIndex],
- 0,
- 0);
- VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage(
- renderer,
- vulkanCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_PRESENT,
- swapchainTextureSubresource);
- }
- if (performCleanups &&
- renderer->allocationsToDefragCount > 0 &&
- !renderer->defragInProgress) {
- if (!VULKAN_INTERNAL_DefragmentMemory(renderer, vulkanCommandBuffer))
- {
- SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s", "Failed to defragment memory, likely OOM!");
- }
- }
- if (!VULKAN_INTERNAL_EndCommandBuffer(renderer, vulkanCommandBuffer)) {
- SDL_UnlockMutex(renderer->submitLock);
- return false;
- }
- vulkanCommandBuffer->inFlightFence = VULKAN_INTERNAL_AcquireFenceFromPool(renderer);
- if (vulkanCommandBuffer->inFlightFence == NULL) {
- SDL_UnlockMutex(renderer->submitLock);
- return false;
- }
- // Command buffer has a reference to the in-flight fence
- (void)SDL_AtomicIncRef(&vulkanCommandBuffer->inFlightFence->referenceCount);
- submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submitInfo.pNext = NULL;
- submitInfo.commandBufferCount = 1;
- submitInfo.pCommandBuffers = &vulkanCommandBuffer->commandBuffer;
- submitInfo.pWaitDstStageMask = waitStages;
- submitInfo.pWaitSemaphores = vulkanCommandBuffer->waitSemaphores;
- submitInfo.waitSemaphoreCount = vulkanCommandBuffer->waitSemaphoreCount;
- submitInfo.pSignalSemaphores = vulkanCommandBuffer->signalSemaphores;
- submitInfo.signalSemaphoreCount = vulkanCommandBuffer->signalSemaphoreCount;
- vulkanResult = renderer->vkQueueSubmit(
- renderer->unifiedQueue,
- 1,
- &submitInfo,
- vulkanCommandBuffer->inFlightFence->fence);
- if (vulkanResult != VK_SUCCESS) {
- SDL_UnlockMutex(renderer->submitLock);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkQueueSubmit, false);
- }
- // Present, if applicable
- for (Uint32 j = 0; j < vulkanCommandBuffer->presentDataCount; j += 1) {
- presentData = &vulkanCommandBuffer->presentDatas[j];
- presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
- presentInfo.pNext = NULL;
- presentInfo.pWaitSemaphores =
- &presentData->windowData->renderFinishedSemaphore[presentData->swapchainImageIndex];
- presentInfo.waitSemaphoreCount = 1;
- presentInfo.pSwapchains = &presentData->windowData->swapchain;
- presentInfo.swapchainCount = 1;
- presentInfo.pImageIndices = &presentData->swapchainImageIndex;
- presentInfo.pResults = NULL;
- presentResult = renderer->vkQueuePresentKHR(
- renderer->unifiedQueue,
- &presentInfo);
- if (presentResult == VK_SUCCESS || presentResult == VK_SUBOPTIMAL_KHR || presentResult == VK_ERROR_OUT_OF_DATE_KHR) {
- // If presenting, the swapchain is using the in-flight fence
- presentData->windowData->inFlightFences[presentData->windowData->frameCounter] = (SDL_GPUFence *)vulkanCommandBuffer->inFlightFence;
- (void)SDL_AtomicIncRef(&vulkanCommandBuffer->inFlightFence->referenceCount);
- // On the Android platform, VK_SUBOPTIMAL_KHR is returned whenever the device is rotated. We'll just ignore this for now.
- #ifndef SDL_PLATFORM_ANDROID
- if (presentResult == VK_SUBOPTIMAL_KHR) {
- presentData->windowData->needsSwapchainRecreate = true;
- }
- #endif
- if (presentResult == VK_ERROR_OUT_OF_DATE_KHR) {
- presentData->windowData->needsSwapchainRecreate = true;
- }
- } else if (presentResult == VK_ERROR_SURFACE_LOST_KHR) {
- // Android can destroy the surface at any time when the app goes into the background,
- // even after successfully acquiring a swapchain texture and before presenting it.
- presentData->windowData->needsSwapchainRecreate = true;
- presentData->windowData->needsSurfaceRecreate = true;
- } else {
- if (presentResult != VK_SUCCESS) {
- VULKAN_INTERNAL_ReleaseCommandBuffer(vulkanCommandBuffer);
- SDL_UnlockMutex(renderer->submitLock);
- }
- CHECK_VULKAN_ERROR_AND_RETURN(presentResult, vkQueuePresentKHR, false);
- }
- presentData->windowData->frameCounter =
- (presentData->windowData->frameCounter + 1) % renderer->allowedFramesInFlight;
- }
- if (performCleanups) {
- for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) {
- vulkanResult = renderer->vkGetFenceStatus(
- renderer->logicalDevice,
- renderer->submittedCommandBuffers[i]->inFlightFence->fence);
- if (vulkanResult == VK_SUCCESS) {
- VULKAN_INTERNAL_CleanCommandBuffer(
- renderer,
- renderer->submittedCommandBuffers[i],
- false);
- }
- }
- if (renderer->checkEmptyAllocations) {
- SDL_LockMutex(renderer->allocatorLock);
- for (Uint32 i = 0; i < VK_MAX_MEMORY_TYPES; i += 1) {
- allocator = &renderer->memoryAllocator->subAllocators[i];
- for (Sint32 j = allocator->allocationCount - 1; j >= 0; j -= 1) {
- if (allocator->allocations[j]->usedRegionCount == 0) {
- VULKAN_INTERNAL_DeallocateMemory(
- renderer,
- allocator,
- j);
- }
- }
- }
- renderer->checkEmptyAllocations = false;
- SDL_UnlockMutex(renderer->allocatorLock);
- }
- VULKAN_INTERNAL_PerformPendingDestroys(renderer);
- }
- // Mark command buffer as submitted
- VULKAN_INTERNAL_ReleaseCommandBuffer(vulkanCommandBuffer);
- SDL_UnlockMutex(renderer->submitLock);
- return true;
- }
- static bool VULKAN_Cancel(
- SDL_GPUCommandBuffer *commandBuffer)
- {
- VulkanRenderer *renderer;
- VulkanCommandBuffer *vulkanCommandBuffer;
- VkResult result;
- vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer;
- renderer = vulkanCommandBuffer->renderer;
- result = renderer->vkResetCommandBuffer(
- vulkanCommandBuffer->commandBuffer,
- VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
- CHECK_VULKAN_ERROR_AND_RETURN(result, vkResetCommandBuffer, false);
- vulkanCommandBuffer->autoReleaseFence = false;
- SDL_LockMutex(renderer->submitLock);
- VULKAN_INTERNAL_CleanCommandBuffer(renderer, vulkanCommandBuffer, true);
- SDL_UnlockMutex(renderer->submitLock);
- return true;
- }
- static bool VULKAN_INTERNAL_DefragmentMemory(
- VulkanRenderer *renderer,
- VulkanCommandBuffer *commandBuffer)
- {
- renderer->defragInProgress = 1;
- commandBuffer->isDefrag = 1;
- SDL_LockMutex(renderer->allocatorLock);
- VulkanMemoryAllocation *allocation = renderer->allocationsToDefrag[renderer->allocationsToDefragCount - 1];
- renderer->allocationsToDefragCount -= 1;
- /* For each used region in the allocation
- * create a new resource, copy the data
- * and re-point the resource containers
- */
- for (Uint32 i = 0; i < allocation->usedRegionCount; i += 1) {
- VulkanMemoryUsedRegion *currentRegion = allocation->usedRegions[i];
- if (currentRegion->isBuffer && !currentRegion->vulkanBuffer->markedForDestroy) {
- VulkanBuffer *newBuffer = VULKAN_INTERNAL_CreateBuffer(
- renderer,
- currentRegion->vulkanBuffer->size,
- currentRegion->vulkanBuffer->usage,
- currentRegion->vulkanBuffer->type,
- false,
- currentRegion->vulkanBuffer->container != NULL ? currentRegion->vulkanBuffer->container->debugName : NULL);
- if (newBuffer == NULL) {
- SDL_UnlockMutex(renderer->allocatorLock);
- SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s", "Failed to allocate defrag buffer!");
- return false;
- }
- // Copy buffer contents if necessary
- if (
- currentRegion->vulkanBuffer->type == VULKAN_BUFFER_TYPE_GPU && currentRegion->vulkanBuffer->transitioned) {
- VULKAN_INTERNAL_BufferTransitionFromDefaultUsage(
- renderer,
- commandBuffer,
- VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE,
- currentRegion->vulkanBuffer);
- VULKAN_INTERNAL_BufferTransitionFromDefaultUsage(
- renderer,
- commandBuffer,
- VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION,
- newBuffer);
- VkBufferCopy bufferCopy;
- bufferCopy.srcOffset = 0;
- bufferCopy.dstOffset = 0;
- bufferCopy.size = currentRegion->resourceSize;
- renderer->vkCmdCopyBuffer(
- commandBuffer->commandBuffer,
- currentRegion->vulkanBuffer->buffer,
- newBuffer->buffer,
- 1,
- &bufferCopy);
- VULKAN_INTERNAL_BufferTransitionToDefaultUsage(
- renderer,
- commandBuffer,
- VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION,
- newBuffer);
- VULKAN_INTERNAL_TrackBuffer(commandBuffer, currentRegion->vulkanBuffer);
- VULKAN_INTERNAL_TrackBuffer(commandBuffer, newBuffer);
- }
- // re-point original container to new buffer
- newBuffer->container = currentRegion->vulkanBuffer->container;
- newBuffer->containerIndex = currentRegion->vulkanBuffer->containerIndex;
- if (newBuffer->type == VULKAN_BUFFER_TYPE_UNIFORM) {
- currentRegion->vulkanBuffer->uniformBufferForDefrag->buffer = newBuffer;
- } else {
- newBuffer->container->buffers[newBuffer->containerIndex] = newBuffer;
- if (newBuffer->container->activeBuffer == currentRegion->vulkanBuffer) {
- newBuffer->container->activeBuffer = newBuffer;
- }
- }
- if (currentRegion->vulkanBuffer->uniformBufferForDefrag) {
- newBuffer->uniformBufferForDefrag = currentRegion->vulkanBuffer->uniformBufferForDefrag;
- }
- VULKAN_INTERNAL_ReleaseBuffer(renderer, currentRegion->vulkanBuffer);
- } else if (!currentRegion->isBuffer && !currentRegion->vulkanTexture->markedForDestroy) {
- VulkanTexture *newTexture = VULKAN_INTERNAL_CreateTexture(
- renderer,
- false,
- ¤tRegion->vulkanTexture->container->header.info);
- if (newTexture == NULL) {
- SDL_UnlockMutex(renderer->allocatorLock);
- SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s", "Failed to allocate defrag buffer!");
- return false;
- }
- SDL_GPUTextureCreateInfo info = currentRegion->vulkanTexture->container->header.info;
- for (Uint32 subresourceIndex = 0; subresourceIndex < currentRegion->vulkanTexture->subresourceCount; subresourceIndex += 1) {
- // copy subresource if necessary
- VulkanTextureSubresource *srcSubresource = ¤tRegion->vulkanTexture->subresources[subresourceIndex];
- VulkanTextureSubresource *dstSubresource = &newTexture->subresources[subresourceIndex];
- VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage(
- renderer,
- commandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE,
- srcSubresource);
- VULKAN_INTERNAL_TextureSubresourceMemoryBarrier(
- renderer,
- commandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED,
- VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION,
- dstSubresource);
- VkImageCopy imageCopy;
- imageCopy.srcOffset.x = 0;
- imageCopy.srcOffset.y = 0;
- imageCopy.srcOffset.z = 0;
- imageCopy.srcSubresource.aspectMask = srcSubresource->parent->aspectFlags;
- imageCopy.srcSubresource.baseArrayLayer = srcSubresource->layer;
- imageCopy.srcSubresource.layerCount = 1;
- imageCopy.srcSubresource.mipLevel = srcSubresource->level;
- imageCopy.extent.width = SDL_max(1, info.width >> srcSubresource->level);
- imageCopy.extent.height = SDL_max(1, info.height >> srcSubresource->level);
- imageCopy.extent.depth = info.type == SDL_GPU_TEXTURETYPE_3D ? info.layer_count_or_depth : 1;
- imageCopy.dstOffset.x = 0;
- imageCopy.dstOffset.y = 0;
- imageCopy.dstOffset.z = 0;
- imageCopy.dstSubresource.aspectMask = dstSubresource->parent->aspectFlags;
- imageCopy.dstSubresource.baseArrayLayer = dstSubresource->layer;
- imageCopy.dstSubresource.layerCount = 1;
- imageCopy.dstSubresource.mipLevel = dstSubresource->level;
- renderer->vkCmdCopyImage(
- commandBuffer->commandBuffer,
- currentRegion->vulkanTexture->image,
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- newTexture->image,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- 1,
- &imageCopy);
- VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
- renderer,
- commandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION,
- dstSubresource);
- VULKAN_INTERNAL_TrackTexture(commandBuffer, srcSubresource->parent);
- VULKAN_INTERNAL_TrackTexture(commandBuffer, dstSubresource->parent);
- }
- // re-point original container to new texture
- newTexture->container = currentRegion->vulkanTexture->container;
- newTexture->containerIndex = currentRegion->vulkanTexture->containerIndex;
- newTexture->container->textures[currentRegion->vulkanTexture->containerIndex] = newTexture;
- if (currentRegion->vulkanTexture == currentRegion->vulkanTexture->container->activeTexture) {
- newTexture->container->activeTexture = newTexture;
- }
- VULKAN_INTERNAL_ReleaseTexture(renderer, currentRegion->vulkanTexture);
- }
- }
- SDL_UnlockMutex(renderer->allocatorLock);
- return true;
- }
- // Format Info
- static bool VULKAN_SupportsTextureFormat(
- SDL_GPURenderer *driverData,
- SDL_GPUTextureFormat format,
- SDL_GPUTextureType type,
- SDL_GPUTextureUsageFlags usage)
- {
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- VkFormat vulkanFormat = SDLToVK_TextureFormat[format];
- VkImageUsageFlags vulkanUsage = 0;
- VkImageCreateFlags createFlags = 0;
- VkImageFormatProperties properties;
- VkResult vulkanResult;
- if (usage & SDL_GPU_TEXTUREUSAGE_SAMPLER) {
- vulkanUsage |= VK_IMAGE_USAGE_SAMPLED_BIT;
- }
- if (usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) {
- vulkanUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
- }
- if (usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) {
- vulkanUsage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
- }
- if (usage & (SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ |
- SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ |
- SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE |
- SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE)) {
- vulkanUsage |= VK_IMAGE_USAGE_STORAGE_BIT;
- }
- if (type == SDL_GPU_TEXTURETYPE_CUBE || type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) {
- createFlags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
- }
- vulkanResult = renderer->vkGetPhysicalDeviceImageFormatProperties(
- renderer->physicalDevice,
- vulkanFormat,
- (type == SDL_GPU_TEXTURETYPE_3D) ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D,
- VK_IMAGE_TILING_OPTIMAL,
- vulkanUsage,
- createFlags,
- &properties);
- return vulkanResult == VK_SUCCESS;
- }
- // Device instantiation
- static inline Uint8 CheckDeviceExtensions(
- VkExtensionProperties *extensions,
- Uint32 numExtensions,
- VulkanExtensions *supports)
- {
- Uint32 i;
- SDL_memset(supports, '\0', sizeof(VulkanExtensions));
- for (i = 0; i < numExtensions; i += 1) {
- const char *name = extensions[i].extensionName;
- #define CHECK(ext) \
- if (SDL_strcmp(name, "VK_" #ext) == 0) { \
- supports->ext = 1; \
- }
- CHECK(KHR_swapchain)
- else CHECK(KHR_maintenance1) else CHECK(KHR_driver_properties) else CHECK(KHR_portability_subset) else CHECK(MSFT_layered_driver) else CHECK(EXT_texture_compression_astc_hdr)
- #undef CHECK
- }
- return (supports->KHR_swapchain &&
- supports->KHR_maintenance1);
- }
- static inline Uint32 GetDeviceExtensionCount(VulkanExtensions *supports)
- {
- return (
- supports->KHR_swapchain +
- supports->KHR_maintenance1 +
- supports->KHR_driver_properties +
- supports->KHR_portability_subset +
- supports->MSFT_layered_driver +
- supports->EXT_texture_compression_astc_hdr);
- }
- static inline void CreateDeviceExtensionArray(
- VulkanExtensions *supports,
- const char **extensions)
- {
- Uint8 cur = 0;
- #define CHECK(ext) \
- if (supports->ext) { \
- extensions[cur++] = "VK_" #ext; \
- }
- CHECK(KHR_swapchain)
- CHECK(KHR_maintenance1)
- CHECK(KHR_driver_properties)
- CHECK(KHR_portability_subset)
- CHECK(MSFT_layered_driver)
- CHECK(EXT_texture_compression_astc_hdr)
- #undef CHECK
- }
- static inline Uint8 SupportsInstanceExtension(
- const char *ext,
- VkExtensionProperties *availableExtensions,
- Uint32 numAvailableExtensions)
- {
- Uint32 i;
- for (i = 0; i < numAvailableExtensions; i += 1) {
- if (SDL_strcmp(ext, availableExtensions[i].extensionName) == 0) {
- return 1;
- }
- }
- return 0;
- }
- static Uint8 VULKAN_INTERNAL_CheckInstanceExtensions(
- const char **requiredExtensions,
- Uint32 requiredExtensionsLength,
- bool *supportsDebugUtils,
- bool *supportsColorspace,
- bool *supportsPhysicalDeviceProperties2,
- int *firstUnsupportedExtensionIndex)
- {
- Uint32 extensionCount, i;
- VkExtensionProperties *availableExtensions;
- Uint8 allExtensionsSupported = 1;
- vkEnumerateInstanceExtensionProperties(
- NULL,
- &extensionCount,
- NULL);
- availableExtensions = SDL_malloc(
- extensionCount * sizeof(VkExtensionProperties));
- vkEnumerateInstanceExtensionProperties(
- NULL,
- &extensionCount,
- availableExtensions);
- for (i = 0; i < requiredExtensionsLength; i += 1) {
- if (!SupportsInstanceExtension(
- requiredExtensions[i],
- availableExtensions,
- extensionCount)) {
- allExtensionsSupported = 0;
- *firstUnsupportedExtensionIndex = i;
- break;
- }
- }
- // This is optional, but nice to have!
- *supportsDebugUtils = SupportsInstanceExtension(
- VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
- availableExtensions,
- extensionCount);
- // Also optional and nice to have!
- *supportsColorspace = SupportsInstanceExtension(
- VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME,
- availableExtensions,
- extensionCount);
- // Only needed for KHR_driver_properties!
- *supportsPhysicalDeviceProperties2 = SupportsInstanceExtension(
- VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
- availableExtensions,
- extensionCount);
- SDL_free(availableExtensions);
- return allExtensionsSupported;
- }
- static Uint8 CheckOptInDeviceExtensions(VulkanFeatures *features,
- Uint32 numExtensions,
- VkExtensionProperties *availableExtensions,
- const char **missingExtensionName) {
- Uint8 supportsAll = 1;
- for (Uint32 extensionIdx = 0; extensionIdx < features->additionalDeviceExtensionCount; extensionIdx++) {
- bool found = false;
- for (Uint32 searchIdx = 0; searchIdx < numExtensions; searchIdx++) {
- if (SDL_strcmp(features->additionalDeviceExtensionNames[extensionIdx], availableExtensions[searchIdx].extensionName) == 0) {
- found = true;
- break;
- }
- }
- if (!found) {
- supportsAll = 0;
- *missingExtensionName = features->additionalDeviceExtensionNames[extensionIdx];
- break;
- }
- }
- return supportsAll;
- }
- static Uint8 VULKAN_INTERNAL_CheckDeviceExtensions(
- VulkanRenderer *renderer,
- VulkanFeatures *features,
- VkPhysicalDevice physicalDevice,
- VulkanExtensions *physicalDeviceExtensions)
- {
- Uint32 extensionCount;
- VkExtensionProperties *availableExtensions;
- Uint8 allExtensionsSupported;
- renderer->vkEnumerateDeviceExtensionProperties(
- physicalDevice,
- NULL,
- &extensionCount,
- NULL);
- availableExtensions = (VkExtensionProperties *)SDL_malloc(
- extensionCount * sizeof(VkExtensionProperties));
- renderer->vkEnumerateDeviceExtensionProperties(
- physicalDevice,
- NULL,
- &extensionCount,
- availableExtensions);
- allExtensionsSupported = CheckDeviceExtensions(
- availableExtensions,
- extensionCount,
- physicalDeviceExtensions);
- if (features->usesCustomVulkanOptions) {
- const char *missingExtensionName;
- if (!CheckOptInDeviceExtensions(features, extensionCount, availableExtensions, &missingExtensionName)) {
- SDL_assert(missingExtensionName);
- if (renderer->debugMode) {
- SDL_LogError(SDL_LOG_CATEGORY_GPU,
- "Required Vulkan device extension '%s' not supported",
- missingExtensionName);
- }
- allExtensionsSupported = 0;
- }
- }
- SDL_free(availableExtensions);
- return allExtensionsSupported;
- }
- static Uint8 VULKAN_INTERNAL_CheckValidationLayers(
- const char **validationLayers,
- Uint32 validationLayersLength)
- {
- Uint32 layerCount;
- VkLayerProperties *availableLayers;
- Uint32 i, j;
- Uint8 layerFound = 0;
- vkEnumerateInstanceLayerProperties(&layerCount, NULL);
- availableLayers = (VkLayerProperties *)SDL_malloc(
- layerCount * sizeof(VkLayerProperties));
- vkEnumerateInstanceLayerProperties(&layerCount, availableLayers);
- for (i = 0; i < validationLayersLength; i += 1) {
- layerFound = 0;
- for (j = 0; j < layerCount; j += 1) {
- if (SDL_strcmp(validationLayers[i], availableLayers[j].layerName) == 0) {
- layerFound = 1;
- break;
- }
- }
- if (!layerFound) {
- break;
- }
- }
- SDL_free(availableLayers);
- return layerFound;
- }
- #define CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, feature, result) \
- if (requested->feature && !supported->feature) { \
- SDL_LogVerbose( \
- SDL_LOG_CATEGORY_GPU, \
- "SDL GPU Vulkan: Application requested unsupported physical device feature '" #feature "'"); \
- result = false; \
- }
- static bool VULKAN_INTERNAL_ValidateOptInVulkan10Features(VkPhysicalDeviceFeatures *requested, VkPhysicalDeviceFeatures *supported)
- {
- if (requested && supported) {
- bool result = true;
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, robustBufferAccess, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, fullDrawIndexUint32, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, imageCubeArray, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, independentBlend, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, geometryShader, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, tessellationShader, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sampleRateShading, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, dualSrcBlend, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, logicOp, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, multiDrawIndirect, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, drawIndirectFirstInstance, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, depthClamp, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, depthBiasClamp, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, fillModeNonSolid, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, depthBounds, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, wideLines, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, largePoints, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, alphaToOne, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, multiViewport, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, samplerAnisotropy, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, textureCompressionETC2, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, textureCompressionASTC_LDR, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, textureCompressionBC, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, occlusionQueryPrecise, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, pipelineStatisticsQuery, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, vertexPipelineStoresAndAtomics, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, fragmentStoresAndAtomics, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderTessellationAndGeometryPointSize, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderImageGatherExtended, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageImageExtendedFormats, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageImageMultisample, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageImageReadWithoutFormat, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageImageWriteWithoutFormat, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderUniformBufferArrayDynamicIndexing, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderSampledImageArrayDynamicIndexing, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageBufferArrayDynamicIndexing, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageImageArrayDynamicIndexing, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderClipDistance, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderCullDistance, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderFloat64, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderInt64, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderInt16, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderResourceResidency, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderResourceMinLod, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseBinding, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidencyBuffer, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidencyImage2D, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidencyImage3D, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidency2Samples, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidency4Samples, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidency8Samples, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidency16Samples, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidencyAliased, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, variableMultisampleRate, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, inheritedQueries, result)
- return result;
- } else {
- return false;
- }
- }
- static bool VULKAN_INTERNAL_ValidateOptInVulkan11Features(VkPhysicalDeviceVulkan11Features *requested, VkPhysicalDeviceVulkan11Features *supported)
- {
- if (requested && supported) {
- bool result = true;
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, storageBuffer16BitAccess, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, uniformAndStorageBuffer16BitAccess, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, storagePushConstant16, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, storageInputOutput16, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, multiview, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, multiviewGeometryShader, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, multiviewTessellationShader, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, variablePointersStorageBuffer, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, variablePointers, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, protectedMemory, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, samplerYcbcrConversion, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderDrawParameters, result)
- return result;
- } else {
- return false;
- }
- }
- static bool VULKAN_INTERNAL_ValidateOptInVulkan12Features(VkPhysicalDeviceVulkan12Features *requested, VkPhysicalDeviceVulkan12Features *supported)
- {
- if (requested && supported) {
- bool result = true;
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, samplerMirrorClampToEdge, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, drawIndirectCount, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, storageBuffer8BitAccess, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, uniformAndStorageBuffer8BitAccess, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, storagePushConstant8, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderBufferInt64Atomics, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderSharedInt64Atomics, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderFloat16, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderInt8, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorIndexing, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderInputAttachmentArrayDynamicIndexing, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderUniformTexelBufferArrayDynamicIndexing, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageTexelBufferArrayDynamicIndexing, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderUniformBufferArrayNonUniformIndexing, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderSampledImageArrayNonUniformIndexing, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageBufferArrayNonUniformIndexing, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageImageArrayNonUniformIndexing, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderInputAttachmentArrayNonUniformIndexing, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderUniformTexelBufferArrayNonUniformIndexing, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageTexelBufferArrayNonUniformIndexing, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingUniformBufferUpdateAfterBind, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingSampledImageUpdateAfterBind, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingStorageImageUpdateAfterBind, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingStorageBufferUpdateAfterBind, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingUniformTexelBufferUpdateAfterBind, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingStorageTexelBufferUpdateAfterBind, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingUpdateUnusedWhilePending, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingPartiallyBound, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingVariableDescriptorCount, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, runtimeDescriptorArray, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, samplerFilterMinmax, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, scalarBlockLayout, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, imagelessFramebuffer, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, uniformBufferStandardLayout, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderSubgroupExtendedTypes, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, separateDepthStencilLayouts, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, hostQueryReset, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, timelineSemaphore, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, bufferDeviceAddress, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, bufferDeviceAddressCaptureReplay, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, bufferDeviceAddressMultiDevice, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, vulkanMemoryModel, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, vulkanMemoryModelDeviceScope, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, vulkanMemoryModelAvailabilityVisibilityChains, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderOutputViewportIndex, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderOutputLayer, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, subgroupBroadcastDynamicId, result)
- return result;
- } else {
- return false;
- }
- }
- static bool VULKAN_INTERNAL_ValidateOptInVulkan13Features(VkPhysicalDeviceVulkan13Features *requested, VkPhysicalDeviceVulkan13Features *supported)
- {
- if (requested && supported) {
- bool result = true;
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, robustImageAccess, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, inlineUniformBlock, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingInlineUniformBlockUpdateAfterBind, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, pipelineCreationCacheControl, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, privateData, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderDemoteToHelperInvocation, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderTerminateInvocation, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, subgroupSizeControl, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, computeFullSubgroups, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, synchronization2, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, textureCompressionASTC_HDR, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderZeroInitializeWorkgroupMemory, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, dynamicRendering, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderIntegerDotProduct, result)
- CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, maintenance4, result)
- return result;
- } else {
- return false;
- }
- }
- #undef CHECK_OPTIONAL_DEVICE_FEATURE
- static bool VULKAN_INTERNAL_ValidateOptInFeatures(VulkanRenderer *renderer, VulkanFeatures *features, VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures *vk10Features)
- {
- bool supportsAllFeatures = true;
- int minorVersion = VK_API_VERSION_MINOR(features->desiredApiVersion);
- if (minorVersion < 1) {
- supportsAllFeatures &= VULKAN_INTERNAL_ValidateOptInVulkan10Features(&features->desiredVulkan10DeviceFeatures, vk10Features);
- } else if (minorVersion < 2) {
- // Query device features using the pre-1.2 structures
- VkPhysicalDevice16BitStorageFeatures storage = { 0 };
- storage.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES;
- VkPhysicalDeviceMultiviewFeatures multiview = { 0 };
- multiview.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
- VkPhysicalDeviceProtectedMemoryFeatures protectedMem = { 0 };
- protectedMem.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES;
- VkPhysicalDeviceSamplerYcbcrConversionFeatures ycbcr = { 0 };
- ycbcr.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
- VkPhysicalDeviceShaderDrawParametersFeatures drawParams = { 0 };
- drawParams.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES;
- VkPhysicalDeviceVariablePointersFeatures varPointers = { 0 };
- varPointers.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES;
- VkPhysicalDeviceFeatures2 supportedFeatureList = { 0 };
- supportedFeatureList.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
- supportedFeatureList.pNext = &storage;
- storage.pNext = &multiview;
- multiview.pNext = &protectedMem;
- protectedMem.pNext = &ycbcr;
- ycbcr.pNext = &drawParams;
- drawParams.pNext = &varPointers;
- renderer->vkGetPhysicalDeviceFeatures2(physicalDevice, &supportedFeatureList);
- // Pack the results into the post-1.2 structure for easier checking
- VkPhysicalDeviceVulkan11Features vk11Features = { 0 };
- vk11Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
- vk11Features.storageBuffer16BitAccess = storage.storageBuffer16BitAccess;
- vk11Features.uniformAndStorageBuffer16BitAccess = storage.uniformAndStorageBuffer16BitAccess;
- vk11Features.storagePushConstant16 = storage.storagePushConstant16;
- vk11Features.storageInputOutput16 = storage.storageInputOutput16;
- vk11Features.multiview = multiview.multiview;
- vk11Features.multiviewGeometryShader = multiview.multiviewGeometryShader;
- vk11Features.multiviewTessellationShader = multiview.multiviewTessellationShader;
- vk11Features.protectedMemory = protectedMem.protectedMemory;
- vk11Features.samplerYcbcrConversion = ycbcr.samplerYcbcrConversion;
- vk11Features.shaderDrawParameters = drawParams.shaderDrawParameters;
- vk11Features.variablePointers = varPointers.variablePointers;
- vk11Features.variablePointersStorageBuffer = varPointers.variablePointersStorageBuffer;
- // Check support
- supportsAllFeatures &= VULKAN_INTERNAL_ValidateOptInVulkan10Features(&features->desiredVulkan10DeviceFeatures, vk10Features);
- supportsAllFeatures &= VULKAN_INTERNAL_ValidateOptInVulkan11Features(&features->desiredVulkan11DeviceFeatures, &vk11Features);
- } else {
- VkPhysicalDeviceVulkan11Features vk11Features = { 0 };
- vk11Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
- VkPhysicalDeviceVulkan12Features vk12Features = { 0 };
- vk12Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
- VkPhysicalDeviceVulkan13Features vk13Features = { 0 };
- vk13Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
- VkPhysicalDeviceFeatures2 supportedFeatureList = { 0 };
- supportedFeatureList.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
- supportedFeatureList.pNext = &vk11Features;
- vk11Features.pNext = &vk12Features;
- vk12Features.pNext = &vk13Features;
- renderer->vkGetPhysicalDeviceFeatures2(physicalDevice, &supportedFeatureList);
- supportsAllFeatures &= VULKAN_INTERNAL_ValidateOptInVulkan10Features(&features->desiredVulkan10DeviceFeatures, vk10Features);
- supportsAllFeatures &= VULKAN_INTERNAL_ValidateOptInVulkan11Features(&features->desiredVulkan11DeviceFeatures, &vk11Features);
- supportsAllFeatures &= VULKAN_INTERNAL_ValidateOptInVulkan12Features(&features->desiredVulkan12DeviceFeatures, &vk12Features);
- supportsAllFeatures &= VULKAN_INTERNAL_ValidateOptInVulkan13Features(&features->desiredVulkan13DeviceFeatures, &vk13Features);
- }
- return supportsAllFeatures;
- }
- static void VULKAN_INTERNAL_AddDeviceFeatures(VkBool32 *firstFeature, VkBool32 *lastFeature, VkBool32 *firstFeatureToAdd)
- {
- while (firstFeature <= lastFeature) {
- *firstFeature = (*firstFeature | *firstFeatureToAdd);
- firstFeature++;
- firstFeatureToAdd++;
- }
- }
- static bool VULKAN_INTERNAL_TryAddDeviceFeatures_Vulkan_11(VkPhysicalDeviceFeatures *dst10,
- VkPhysicalDeviceVulkan11Features *dst11,
- VkBaseOutStructure *src)
- {
- bool hasAdded = false;
- switch (src->sType) {
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2:
- {
- VkPhysicalDeviceFeatures2 *newFeatures = (VkPhysicalDeviceFeatures2 *)src;
- VULKAN_INTERNAL_AddDeviceFeatures(&dst10->robustBufferAccess,
- &dst10->inheritedQueries,
- &newFeatures->features.robustBufferAccess);
- hasAdded = true;
- } break;
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES:
- {
- VkPhysicalDevice16BitStorageFeatures *newFeatures = (VkPhysicalDevice16BitStorageFeatures *)src;
- dst11->storageBuffer16BitAccess |= newFeatures->storageBuffer16BitAccess;
- dst11->uniformAndStorageBuffer16BitAccess |= newFeatures->uniformAndStorageBuffer16BitAccess;
- dst11->storagePushConstant16 |= newFeatures->storagePushConstant16;
- dst11->storageInputOutput16 |= newFeatures->storageInputOutput16;
- hasAdded = true;
- } break;
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES:
- {
- VkPhysicalDeviceMultiviewFeatures *newFeatures = (VkPhysicalDeviceMultiviewFeatures *)src;
- dst11->multiview |= newFeatures->multiview;
- dst11->multiviewGeometryShader |= newFeatures->multiviewGeometryShader;
- dst11->multiviewTessellationShader |= newFeatures->multiviewTessellationShader;
- hasAdded = true;
- } break;
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES:
- {
- VkPhysicalDeviceProtectedMemoryFeatures *newFeatures = (VkPhysicalDeviceProtectedMemoryFeatures *)src;
- dst11->protectedMemory |= newFeatures->protectedMemory;
- hasAdded = true;
- } break;
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES:
- {
- VkPhysicalDeviceSamplerYcbcrConversionFeatures *newFeatures = (VkPhysicalDeviceSamplerYcbcrConversionFeatures *)src;
- dst11->samplerYcbcrConversion |= newFeatures->samplerYcbcrConversion;
- hasAdded = true;
- } break;
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES:
- {
- VkPhysicalDeviceShaderDrawParametersFeatures *newFeatures = (VkPhysicalDeviceShaderDrawParametersFeatures *)src;
- dst11->shaderDrawParameters |= newFeatures->shaderDrawParameters;
- hasAdded = true;
- } break;
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES:
- {
- VkPhysicalDeviceVariablePointersFeatures *newFeatures = (VkPhysicalDeviceVariablePointersFeatures *)src;
- dst11->variablePointers |= newFeatures->variablePointers;
- dst11->variablePointersStorageBuffer |= newFeatures->variablePointersStorageBuffer;
- hasAdded = true;
- } break;
- default:
- break;
- }
- return hasAdded;
- }
- static bool VULKAN_INTERNAL_TryAddDeviceFeatures_Vulkan_12_Or_Later(VkPhysicalDeviceFeatures *dst10,
- VkPhysicalDeviceVulkan11Features *dst11,
- VkPhysicalDeviceVulkan12Features *dst12,
- VkPhysicalDeviceVulkan13Features *dst13,
- Uint32 apiVersion,
- VkBaseOutStructure *src)
- {
- int minorVersion = VK_API_VERSION_MINOR(apiVersion);
- SDL_assert(apiVersion >= 2);
- bool hasAdded = VULKAN_INTERNAL_TryAddDeviceFeatures_Vulkan_11(dst10, dst11, src);
- if (!hasAdded) {
- switch (src->sType) {
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES:
- {
- VkPhysicalDeviceVulkan11Features *newFeatures = (VkPhysicalDeviceVulkan11Features *)src;
- VULKAN_INTERNAL_AddDeviceFeatures(&dst11->storageBuffer16BitAccess,
- &dst11->shaderDrawParameters,
- &newFeatures->storageBuffer16BitAccess);
- hasAdded = true;
- } break;
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES:
- {
- VkPhysicalDeviceVulkan12Features *newFeatures = (VkPhysicalDeviceVulkan12Features *)src;
- VULKAN_INTERNAL_AddDeviceFeatures(&dst12->samplerMirrorClampToEdge,
- &dst12->subgroupBroadcastDynamicId,
- &newFeatures->samplerMirrorClampToEdge);
- hasAdded = true;
- } break;
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES:
- {
- if (minorVersion >= 3) {
- VkPhysicalDeviceVulkan13Features *newFeatures = (VkPhysicalDeviceVulkan13Features *)src;
- VULKAN_INTERNAL_AddDeviceFeatures(&dst13->robustImageAccess,
- &dst13->maintenance4,
- &newFeatures->robustImageAccess);
- hasAdded = true;
- }
- } break;
- default:
- break;
- }
- }
- return hasAdded;
- }
- static void VULKAN_INTERNAL_AddOptInVulkanOptions(SDL_PropertiesID props, VulkanRenderer *renderer, VulkanFeatures *features)
- {
- if (SDL_HasProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_OPTIONS_POINTER)) {
- SDL_GPUVulkanOptions *options = (SDL_GPUVulkanOptions *)SDL_GetPointerProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_OPTIONS_POINTER, NULL);
- if (options) {
- features->usesCustomVulkanOptions = true;
- features->desiredApiVersion = options->vulkan_api_version;
- SDL_zero(features->desiredVulkan11DeviceFeatures);
- SDL_zero(features->desiredVulkan12DeviceFeatures);
- SDL_zero(features->desiredVulkan13DeviceFeatures);
- features->desiredVulkan11DeviceFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
- features->desiredVulkan12DeviceFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
- features->desiredVulkan13DeviceFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
- // Handle requested device features
- VkPhysicalDeviceFeatures *vk10Features = &features->desiredVulkan10DeviceFeatures;
- VkPhysicalDeviceVulkan11Features *vk11Features = &features->desiredVulkan11DeviceFeatures;
- VkPhysicalDeviceVulkan12Features *vk12Features = &features->desiredVulkan12DeviceFeatures;
- VkPhysicalDeviceVulkan13Features *vk13Features = &features->desiredVulkan13DeviceFeatures;
- if (options->vulkan_10_physical_device_features) {
- VkPhysicalDeviceFeatures *deviceFeatures = (VkPhysicalDeviceFeatures *)options->vulkan_10_physical_device_features;
- VULKAN_INTERNAL_AddDeviceFeatures(&vk10Features->robustBufferAccess,
- &vk10Features->inheritedQueries,
- &deviceFeatures->robustBufferAccess);
- }
- int minorVersion = VK_API_VERSION_MINOR(features->desiredApiVersion);
- bool supportsHigherLevelFeatures = minorVersion > 0;
- if (supportsHigherLevelFeatures && options->feature_list) {
- if (minorVersion < 2) {
- // Iterate through the entire list and combine all requested features
- VkBaseOutStructure *nextStructure = (VkBaseOutStructure *)options->feature_list;
- while (nextStructure) {
- VULKAN_INTERNAL_TryAddDeviceFeatures_Vulkan_11(vk10Features, vk11Features, nextStructure);
- nextStructure = nextStructure->pNext;
- }
- } else {
- // Iterate through the entire list and combine all requested features
- VkBaseOutStructure *nextStructure = (VkBaseOutStructure *)options->feature_list;
- while (nextStructure) {
- VULKAN_INTERNAL_TryAddDeviceFeatures_Vulkan_12_Or_Later(vk10Features,
- vk11Features,
- vk12Features,
- vk13Features,
- features->desiredApiVersion,
- nextStructure);
- nextStructure = nextStructure->pNext;
- }
- }
- }
- features->additionalDeviceExtensionCount = options->device_extension_count;
- features->additionalDeviceExtensionNames = options->device_extension_names;
- features->additionalInstanceExtensionCount = options->instance_extension_count;
- features->additionalInstanceExtensionNames = options->instance_extension_names;
- } else if (renderer->debugMode) {
- SDL_LogWarn(SDL_LOG_CATEGORY_GPU,
- "VULKAN_INTERNAL_AddOptInVulkanOptions: Additional options property was set, but value was null. This may be a bug.");
- }
- }
- }
- static Uint8 VULKAN_INTERNAL_CreateInstance(VulkanRenderer *renderer, VulkanFeatures *features)
- {
- VkResult vulkanResult;
- VkApplicationInfo appInfo;
- VkInstanceCreateFlags createFlags;
- const char *const *originalInstanceExtensionNames;
- const char **instanceExtensionNames;
- Uint32 instanceExtensionCount;
- VkInstanceCreateInfo createInfo;
- static const char *layerNames[] = { "VK_LAYER_KHRONOS_validation" };
- appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
- appInfo.pNext = NULL;
- appInfo.pApplicationName = NULL;
- appInfo.applicationVersion = 0;
- appInfo.pEngineName = "SDLGPU";
- appInfo.engineVersion = SDL_VERSION;
- appInfo.apiVersion = features->usesCustomVulkanOptions
- ? features->desiredApiVersion
- : VK_MAKE_VERSION(1, 0, 0);
- createFlags = 0;
- originalInstanceExtensionNames = SDL_Vulkan_GetInstanceExtensions(&instanceExtensionCount);
- if (!originalInstanceExtensionNames) {
- SDL_LogError(
- SDL_LOG_CATEGORY_GPU,
- "SDL_Vulkan_GetInstanceExtensions(): getExtensionCount: %s",
- SDL_GetError());
- return 0;
- }
- Uint32 extraInstanceExtensionCount = features->additionalInstanceExtensionCount;
- const char** extraInstanceExtensionNames = features->additionalInstanceExtensionNames;
- /* Extra space for the following extensions:
- * VK_KHR_get_physical_device_properties2
- * VK_EXT_swapchain_colorspace
- * VK_EXT_debug_utils
- * VK_KHR_portability_enumeration
- *
- * Plus additional opt-in extensions.
- */
- instanceExtensionNames = SDL_stack_alloc(
- const char *,
- instanceExtensionCount + 4 + extraInstanceExtensionCount);
- const char** nextInstanceExtensionNamePtr = instanceExtensionNames;
- SDL_memcpy((void *)nextInstanceExtensionNamePtr, originalInstanceExtensionNames, instanceExtensionCount * sizeof(const char *));
- nextInstanceExtensionNamePtr += instanceExtensionCount;
- if (extraInstanceExtensionCount > 0) {
- SDL_memcpy((void *)nextInstanceExtensionNamePtr, extraInstanceExtensionNames, extraInstanceExtensionCount * sizeof(const char *));
- nextInstanceExtensionNamePtr += extraInstanceExtensionCount;
- }
- #ifdef SDL_PLATFORM_APPLE
- *nextInstanceExtensionNamePtr++ = VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME;
- instanceExtensionCount++;
- createFlags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
- #endif
- int firstUnsupportedExtensionIndex = 0;
- if (!VULKAN_INTERNAL_CheckInstanceExtensions(
- instanceExtensionNames,
- instanceExtensionCount + extraInstanceExtensionCount,
- &renderer->supportsDebugUtils,
- &renderer->supportsColorspace,
- &renderer->supportsPhysicalDeviceProperties2,
- &firstUnsupportedExtensionIndex)) {
- if (renderer->debugMode) {
- SDL_LogError(SDL_LOG_CATEGORY_GPU,
- "Required Vulkan instance extension '%s' not supported",
- instanceExtensionNames[firstUnsupportedExtensionIndex]);
- }
- SDL_SetError("Required Vulkan instance extension '%s' not supported",
- instanceExtensionNames[firstUnsupportedExtensionIndex]);
- SDL_stack_free((char *)instanceExtensionNames);
- return false;
- }
- if (renderer->supportsDebugUtils) {
- // Append the debug extension
- *nextInstanceExtensionNamePtr++ = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
- instanceExtensionCount++;
- } else {
- SDL_LogWarn(
- SDL_LOG_CATEGORY_GPU,
- "%s is not supported!",
- VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
- }
- if (renderer->supportsColorspace) {
- // Append colorspace extension
- *nextInstanceExtensionNamePtr++ = VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME;
- instanceExtensionCount++;
- }
- if (renderer->supportsPhysicalDeviceProperties2) {
- // Append KHR_physical_device_properties2 extension
- *nextInstanceExtensionNamePtr++ = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME;
- instanceExtensionCount++;
- }
- createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
- createInfo.pNext = NULL;
- createInfo.flags = createFlags;
- createInfo.pApplicationInfo = &appInfo;
- createInfo.ppEnabledLayerNames = layerNames;
- createInfo.enabledExtensionCount = instanceExtensionCount + extraInstanceExtensionCount;
- createInfo.ppEnabledExtensionNames = instanceExtensionNames;
- if (renderer->debugMode) {
- createInfo.enabledLayerCount = SDL_arraysize(layerNames);
- if (!VULKAN_INTERNAL_CheckValidationLayers(
- layerNames,
- createInfo.enabledLayerCount)) {
- SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Validation layers not found, continuing without validation");
- createInfo.enabledLayerCount = 0;
- } else {
- SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Validation layers enabled, expect debug level performance!");
- }
- } else {
- createInfo.enabledLayerCount = 0;
- }
- vulkanResult = vkCreateInstance(&createInfo, NULL, &renderer->instance);
- SDL_stack_free((char *)instanceExtensionNames);
- if (vulkanResult != VK_SUCCESS) {
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateInstance, 0);
- }
- return 1;
- }
- static bool VULKAN_INTERNAL_GetDeviceRank(
- VulkanRenderer *renderer,
- VkPhysicalDevice physicalDevice,
- VulkanExtensions *physicalDeviceExtensions,
- Uint64 *deviceRank)
- {
- static const Uint8 DEVICE_PRIORITY_HIGHPERFORMANCE[] = {
- 0, // VK_PHYSICAL_DEVICE_TYPE_OTHER
- 3, // VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU
- 4, // VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
- 2, // VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU
- 1 // VK_PHYSICAL_DEVICE_TYPE_CPU
- };
- static const Uint8 DEVICE_PRIORITY_LOWPOWER[] = {
- 0, // VK_PHYSICAL_DEVICE_TYPE_OTHER
- 4, // VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU
- 3, // VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
- 2, // VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU
- 1 // VK_PHYSICAL_DEVICE_TYPE_CPU
- };
- const Uint8 *devicePriority = renderer->preferLowPower ? DEVICE_PRIORITY_LOWPOWER : DEVICE_PRIORITY_HIGHPERFORMANCE;
- VkPhysicalDeviceType deviceType;
- if (physicalDeviceExtensions->MSFT_layered_driver) {
- VkPhysicalDeviceProperties2KHR physicalDeviceProperties;
- VkPhysicalDeviceLayeredDriverPropertiesMSFT physicalDeviceLayeredDriverProperties;
- physicalDeviceProperties.sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
- physicalDeviceProperties.pNext = &physicalDeviceLayeredDriverProperties;
- physicalDeviceLayeredDriverProperties.sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_DRIVER_PROPERTIES_MSFT;
- physicalDeviceLayeredDriverProperties.pNext = NULL;
- renderer->vkGetPhysicalDeviceProperties2KHR(
- physicalDevice,
- &physicalDeviceProperties);
- if (physicalDeviceLayeredDriverProperties.underlyingAPI != VK_LAYERED_DRIVER_UNDERLYING_API_NONE_MSFT) {
- deviceType = VK_PHYSICAL_DEVICE_TYPE_OTHER;
- } else {
- deviceType = physicalDeviceProperties.properties.deviceType;
- }
- } else {
- VkPhysicalDeviceProperties physicalDeviceProperties;
- renderer->vkGetPhysicalDeviceProperties(
- physicalDevice,
- &physicalDeviceProperties);
- deviceType = physicalDeviceProperties.deviceType;
- }
- if (renderer->requireHardwareAcceleration) {
- if (deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU &&
- deviceType != VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU &&
- deviceType != VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU) {
- // In addition to CPU, "Other" drivers (including layered drivers) don't count as hardware-accelerated
- return 0;
- }
- }
- /* Apply a large bias on the devicePriority so that we always respect the order in the priority arrays.
- * We also rank by e.g. VRAM which should have less influence than the device type.
- */
- Uint64 devicePriorityValue = devicePriority[deviceType] * 1000000;
- if (*deviceRank < devicePriorityValue) {
- /* This device outranks the best device we've found so far!
- * This includes a dedicated GPU that has less features than an
- * integrated GPU, because this is a freak case that is almost
- * never intentionally desired by the end user
- */
- *deviceRank = devicePriorityValue;
- } else if (*deviceRank > devicePriorityValue) {
- /* Device is outranked by a previous device, don't even try to
- * run a query and reset the rank to avoid overwrites
- */
- *deviceRank = 0;
- return false;
- }
- /* If we prefer high performance, sum up all device local memory (rounded to megabytes)
- * to deviceRank. In the niche case of someone having multiple dedicated GPUs in the same
- * system, this theoretically picks the most powerful one (or at least the one with the
- * most memory!)
- *
- * We do this *after* discarding all non suitable devices, which means if this computer
- * has multiple dedicated GPUs that all meet our criteria, *and* the user asked for high
- * performance, then we always pick the GPU with more VRAM.
- */
- if (!renderer->preferLowPower) {
- Uint32 i;
- Uint64 videoMemory = 0;
- VkPhysicalDeviceMemoryProperties deviceMemory;
- renderer->vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemory);
- for (i = 0; i < deviceMemory.memoryHeapCount; i++) {
- VkMemoryHeap heap = deviceMemory.memoryHeaps[i];
- if (heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) {
- videoMemory += heap.size;
- }
- }
- // Round it to megabytes (as per the vulkan spec videoMemory is in bytes)
- Uint64 videoMemoryRounded = videoMemory / 1024 / 1024;
- *deviceRank += videoMemoryRounded;
- }
- return true;
- }
- static Uint8 VULKAN_INTERNAL_IsDeviceSuitable(
- VulkanRenderer *renderer,
- VulkanFeatures *features,
- VkPhysicalDevice physicalDevice,
- VulkanExtensions *physicalDeviceExtensions,
- Uint32 *queueFamilyIndex)
- {
- Uint32 queueFamilyCount, queueFamilyRank, queueFamilyBest;
- VkQueueFamilyProperties *queueProps;
- bool supportsPresent;
- VkPhysicalDeviceFeatures deviceFeatures;
- Uint32 i;
- renderer->vkGetPhysicalDeviceFeatures(
- physicalDevice,
- &deviceFeatures);
- if ((!deviceFeatures.independentBlend && features->desiredVulkan10DeviceFeatures.independentBlend) ||
- (!deviceFeatures.imageCubeArray && features->desiredVulkan10DeviceFeatures.imageCubeArray) ||
- (!deviceFeatures.depthClamp && features->desiredVulkan10DeviceFeatures.depthClamp) ||
- (!deviceFeatures.shaderClipDistance && features->desiredVulkan10DeviceFeatures.shaderClipDistance) ||
- (!deviceFeatures.drawIndirectFirstInstance && features->desiredVulkan10DeviceFeatures.drawIndirectFirstInstance) ||
- (!deviceFeatures.sampleRateShading && features->desiredVulkan10DeviceFeatures.sampleRateShading) ||
- (!deviceFeatures.samplerAnisotropy && features->desiredVulkan10DeviceFeatures.samplerAnisotropy)) {
- return 0;
- }
- // Check opt-in device features
- if (features->usesCustomVulkanOptions) {
- bool supportsAllFeatures = VULKAN_INTERNAL_ValidateOptInFeatures(renderer, features, physicalDevice, &deviceFeatures);
- if (!supportsAllFeatures) {
- return 0;
- }
- }
- if (!VULKAN_INTERNAL_CheckDeviceExtensions(
- renderer,
- features,
- physicalDevice,
- physicalDeviceExtensions)) {
- return 0;
- }
- renderer->vkGetPhysicalDeviceQueueFamilyProperties(
- physicalDevice,
- &queueFamilyCount,
- NULL);
- queueProps = SDL_stack_alloc(
- VkQueueFamilyProperties,
- queueFamilyCount);
- renderer->vkGetPhysicalDeviceQueueFamilyProperties(
- physicalDevice,
- &queueFamilyCount,
- queueProps);
- queueFamilyBest = 0;
- *queueFamilyIndex = SDL_MAX_UINT32;
- for (i = 0; i < queueFamilyCount; i += 1) {
- supportsPresent = SDL_Vulkan_GetPresentationSupport(
- renderer->instance,
- physicalDevice,
- i);
- if (!supportsPresent ||
- !(queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)) {
- // Not a graphics family, ignore.
- continue;
- }
- /* The queue family bitflags are kind of annoying.
- *
- * We of course need a graphics family, but we ideally want the
- * _primary_ graphics family. The spec states that at least one
- * graphics family must also be a compute family, so generally
- * drivers make that the first one. But hey, maybe something
- * genuinely can't do compute or something, and FNA doesn't
- * need it, so we'll be open to a non-compute queue family.
- *
- * Additionally, it's common to see the primary queue family
- * have the transfer bit set, which is great! But this is
- * actually optional; it's impossible to NOT have transfers in
- * graphics/compute but it _is_ possible for a graphics/compute
- * family, even the primary one, to just decide not to set the
- * bitflag. Admittedly, a driver may want to isolate transfer
- * queues to a dedicated family so that queues made solely for
- * transfers can have an optimized DMA queue.
- *
- * That, or the driver author got lazy and decided not to set
- * the bit. Looking at you, Android.
- *
- * -flibit
- */
- if (queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) {
- if (queueProps[i].queueFlags & VK_QUEUE_TRANSFER_BIT) {
- // Has all attribs!
- queueFamilyRank = 3;
- } else {
- // Probably has a DMA transfer queue family
- queueFamilyRank = 2;
- }
- } else {
- // Just a graphics family, probably has something better
- queueFamilyRank = 1;
- }
- if (queueFamilyRank > queueFamilyBest) {
- *queueFamilyIndex = i;
- queueFamilyBest = queueFamilyRank;
- }
- }
- SDL_stack_free(queueProps);
- if (*queueFamilyIndex == SDL_MAX_UINT32) {
- // Somehow no graphics queues existed. Compute-only device?
- return 0;
- }
- // FIXME: Need better structure for checking vs storing swapchain support details
- return 1;
- }
- static Uint8 VULKAN_INTERNAL_DeterminePhysicalDevice(VulkanRenderer *renderer, VulkanFeatures *features)
- {
- VkResult vulkanResult;
- VkPhysicalDevice *physicalDevices;
- VulkanExtensions *physicalDeviceExtensions;
- Uint32 i, physicalDeviceCount;
- Sint32 suitableIndex;
- Uint32 suitableQueueFamilyIndex;
- Uint64 highestRank;
- vulkanResult = renderer->vkEnumeratePhysicalDevices(
- renderer->instance,
- &physicalDeviceCount,
- NULL);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkEnumeratePhysicalDevices, 0);
- if (physicalDeviceCount == 0) {
- SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Failed to find any GPUs with Vulkan support");
- return 0;
- }
- physicalDevices = SDL_stack_alloc(VkPhysicalDevice, physicalDeviceCount);
- physicalDeviceExtensions = SDL_stack_alloc(VulkanExtensions, physicalDeviceCount);
- vulkanResult = renderer->vkEnumeratePhysicalDevices(
- renderer->instance,
- &physicalDeviceCount,
- physicalDevices);
- /* This should be impossible to hit, but from what I can tell this can
- * be triggered not because the array is too small, but because there
- * were drivers that turned out to be bogus, so this is the loader's way
- * of telling us that the list is now smaller than expected :shrug:
- */
- if (vulkanResult == VK_INCOMPLETE) {
- SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "vkEnumeratePhysicalDevices returned VK_INCOMPLETE, will keep trying anyway...");
- vulkanResult = VK_SUCCESS;
- }
- if (vulkanResult != VK_SUCCESS) {
- SDL_LogWarn(
- SDL_LOG_CATEGORY_GPU,
- "vkEnumeratePhysicalDevices failed: %s",
- VkErrorMessages(vulkanResult));
- SDL_stack_free(physicalDevices);
- SDL_stack_free(physicalDeviceExtensions);
- return 0;
- }
- // Any suitable device will do, but we'd like the best
- suitableIndex = -1;
- suitableQueueFamilyIndex = 0;
- highestRank = 0;
- for (i = 0; i < physicalDeviceCount; i += 1) {
- Uint32 queueFamilyIndex;
- Uint64 deviceRank;
- if (!VULKAN_INTERNAL_IsDeviceSuitable(
- renderer,
- features,
- physicalDevices[i],
- &physicalDeviceExtensions[i],
- &queueFamilyIndex)) {
- // Device does not meet the minimum requirements, skip it entirely
- continue;
- }
- deviceRank = highestRank;
- if (VULKAN_INTERNAL_GetDeviceRank(
- renderer,
- physicalDevices[i],
- &physicalDeviceExtensions[i],
- &deviceRank)) {
- /* Use this for rendering.
- * Note that this may override a previous device that
- * supports rendering, but shares the same device rank.
- */
- suitableIndex = i;
- suitableQueueFamilyIndex = queueFamilyIndex;
- highestRank = deviceRank;
- }
- }
- if (suitableIndex != -1) {
- renderer->supports = physicalDeviceExtensions[suitableIndex];
- renderer->physicalDevice = physicalDevices[suitableIndex];
- renderer->queueFamilyIndex = suitableQueueFamilyIndex;
- } else {
- SDL_stack_free(physicalDevices);
- SDL_stack_free(physicalDeviceExtensions);
- return 0;
- }
- renderer->physicalDeviceProperties.sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
- if (renderer->supports.KHR_driver_properties) {
- renderer->physicalDeviceDriverProperties.sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR;
- renderer->physicalDeviceDriverProperties.pNext = NULL;
- renderer->physicalDeviceProperties.pNext =
- &renderer->physicalDeviceDriverProperties;
- renderer->vkGetPhysicalDeviceProperties2KHR(
- renderer->physicalDevice,
- &renderer->physicalDeviceProperties);
- /* FIXME: This is very much a last resort to avoid WIP drivers.
- *
- * As far as I know, the only drivers available to users that are also
- * non-conformant are incomplete Mesa drivers. hasvk is one example.
- *
- * It'd be nice to detect this sooner, but if this device is truly the
- * best device on the system, it's the same outcome anyhow.
- * -flibit
- */
- if (renderer->physicalDeviceDriverProperties.conformanceVersion.major < 1) {
- SDL_stack_free(physicalDevices);
- SDL_stack_free(physicalDeviceExtensions);
- return 0;
- }
- } else {
- renderer->physicalDeviceProperties.pNext = NULL;
- renderer->vkGetPhysicalDeviceProperties(
- renderer->physicalDevice,
- &renderer->physicalDeviceProperties.properties);
- }
- renderer->vkGetPhysicalDeviceMemoryProperties(
- renderer->physicalDevice,
- &renderer->memoryProperties);
- SDL_stack_free(physicalDevices);
- SDL_stack_free(physicalDeviceExtensions);
- return 1;
- }
- static Uint8 VULKAN_INTERNAL_CreateLogicalDevice(
- VulkanRenderer *renderer,
- VulkanFeatures *features)
- {
- VkResult vulkanResult;
- VkDeviceCreateInfo deviceCreateInfo;
- VkPhysicalDeviceFeatures haveDeviceFeatures;
- VkPhysicalDevicePortabilitySubsetFeaturesKHR portabilityFeatures;
- const char **deviceExtensions;
- VkDeviceQueueCreateInfo queueCreateInfo;
- float queuePriority = 1.0f;
- queueCreateInfo.sType =
- VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
- queueCreateInfo.pNext = NULL;
- queueCreateInfo.flags = 0;
- queueCreateInfo.queueFamilyIndex = renderer->queueFamilyIndex;
- queueCreateInfo.queueCount = 1;
- queueCreateInfo.pQueuePriorities = &queuePriority;
- // check feature support
- renderer->vkGetPhysicalDeviceFeatures(
- renderer->physicalDevice,
- &haveDeviceFeatures);
- // specifying used device features
- if (haveDeviceFeatures.fillModeNonSolid) {
- features->desiredVulkan10DeviceFeatures.fillModeNonSolid = VK_TRUE;
- renderer->supportsFillModeNonSolid = true;
- }
- if (haveDeviceFeatures.multiDrawIndirect) {
- features->desiredVulkan10DeviceFeatures.multiDrawIndirect = VK_TRUE;
- renderer->supportsMultiDrawIndirect = true;
- }
- // creating the logical device
- deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
- if (renderer->supports.KHR_portability_subset) {
- portabilityFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR;
- portabilityFeatures.pNext = NULL;
- portabilityFeatures.constantAlphaColorBlendFactors = VK_FALSE;
- portabilityFeatures.events = VK_FALSE;
- portabilityFeatures.imageViewFormatReinterpretation = VK_FALSE;
- portabilityFeatures.imageViewFormatSwizzle = VK_TRUE;
- portabilityFeatures.imageView2DOn3DImage = VK_FALSE;
- portabilityFeatures.multisampleArrayImage = VK_FALSE;
- portabilityFeatures.mutableComparisonSamplers = VK_FALSE;
- portabilityFeatures.pointPolygons = VK_FALSE;
- portabilityFeatures.samplerMipLodBias = VK_FALSE; // Technically should be true, but eh
- portabilityFeatures.separateStencilMaskRef = VK_FALSE;
- portabilityFeatures.shaderSampleRateInterpolationFunctions = VK_FALSE;
- portabilityFeatures.tessellationIsolines = VK_FALSE;
- portabilityFeatures.tessellationPointMode = VK_FALSE;
- portabilityFeatures.triangleFans = VK_FALSE;
- portabilityFeatures.vertexAttributeAccessBeyondStride = VK_FALSE;
- deviceCreateInfo.pNext = &portabilityFeatures;
- } else {
- deviceCreateInfo.pNext = NULL;
- }
- deviceCreateInfo.flags = 0;
- deviceCreateInfo.queueCreateInfoCount = 1;
- deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo;
- deviceCreateInfo.enabledLayerCount = 0;
- deviceCreateInfo.ppEnabledLayerNames = NULL;
- deviceCreateInfo.enabledExtensionCount = GetDeviceExtensionCount(
- &renderer->supports);
- deviceExtensions = SDL_stack_alloc(
- const char *,
- deviceCreateInfo.enabledExtensionCount);
- CreateDeviceExtensionArray(&renderer->supports, deviceExtensions);
- deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions;
- VkPhysicalDeviceFeatures2 featureList;
- int minor = VK_VERSION_MINOR(features->desiredApiVersion);
- struct {
- VkPhysicalDevice16BitStorageFeatures storage;
- VkPhysicalDeviceMultiviewFeatures multiview;
- VkPhysicalDeviceProtectedMemoryFeatures protectedMem;
- VkPhysicalDeviceSamplerYcbcrConversionFeatures ycbcr;
- VkPhysicalDeviceShaderDrawParametersFeatures drawParams;
- VkPhysicalDeviceVariablePointersFeatures varPointers;
- } legacyFeatures;
- if (features->usesCustomVulkanOptions && minor > 0) {
- featureList.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
- featureList.features = features->desiredVulkan10DeviceFeatures;
- if (minor > 1) {
- featureList.pNext = &features->desiredVulkan11DeviceFeatures;
- features->desiredVulkan11DeviceFeatures.pNext = &features->desiredVulkan12DeviceFeatures;
- features->desiredVulkan12DeviceFeatures.pNext = minor > 2 ? &features->desiredVulkan13DeviceFeatures : NULL;
- features->desiredVulkan13DeviceFeatures.pNext = NULL;
- } else {
- // Break VkPhysicalDeviceVulkan11Features into pre 1.2 structures for Vulkan 1.1 Support
- SDL_zero(legacyFeatures);
- legacyFeatures.storage.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES;
- legacyFeatures.storage.storageBuffer16BitAccess = features->desiredVulkan11DeviceFeatures.storageBuffer16BitAccess;
- legacyFeatures.storage.storageInputOutput16 = features->desiredVulkan11DeviceFeatures.storageInputOutput16;
- legacyFeatures.storage.storagePushConstant16 = features->desiredVulkan11DeviceFeatures.storagePushConstant16;
- legacyFeatures.storage.uniformAndStorageBuffer16BitAccess = features->desiredVulkan11DeviceFeatures.uniformAndStorageBuffer16BitAccess;
- legacyFeatures.multiview.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
- legacyFeatures.multiview.multiview = features->desiredVulkan11DeviceFeatures.multiview;
- legacyFeatures.multiview.multiviewGeometryShader = features->desiredVulkan11DeviceFeatures.multiviewGeometryShader;
- legacyFeatures.multiview.multiviewTessellationShader = features->desiredVulkan11DeviceFeatures.multiviewTessellationShader;
- legacyFeatures.protectedMem.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES;
- legacyFeatures.protectedMem.protectedMemory = features->desiredVulkan11DeviceFeatures.protectedMemory;
- legacyFeatures.ycbcr.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
- legacyFeatures.ycbcr.samplerYcbcrConversion = features->desiredVulkan11DeviceFeatures.samplerYcbcrConversion;
- legacyFeatures.drawParams.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES;
- legacyFeatures.drawParams.shaderDrawParameters = features->desiredVulkan11DeviceFeatures.shaderDrawParameters;
- legacyFeatures.varPointers.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES;
- legacyFeatures.varPointers.variablePointers = features->desiredVulkan11DeviceFeatures.variablePointers;
- legacyFeatures.varPointers.variablePointersStorageBuffer = features->desiredVulkan11DeviceFeatures.variablePointersStorageBuffer;
- featureList.pNext = &legacyFeatures.storage;
- legacyFeatures.storage.pNext = &legacyFeatures.multiview;
- legacyFeatures.multiview.pNext = &legacyFeatures.protectedMem;
- legacyFeatures.protectedMem.pNext = &legacyFeatures.ycbcr;
- legacyFeatures.ycbcr.pNext = &legacyFeatures.drawParams;
- legacyFeatures.drawParams.pNext = &legacyFeatures.varPointers;
- }
- deviceCreateInfo.pEnabledFeatures = NULL;
- deviceCreateInfo.pNext = &featureList;
- } else {
- deviceCreateInfo.pEnabledFeatures = &features->desiredVulkan10DeviceFeatures;
- }
- vulkanResult = renderer->vkCreateDevice(
- renderer->physicalDevice,
- &deviceCreateInfo,
- NULL,
- &renderer->logicalDevice);
- SDL_stack_free((void *)deviceExtensions);
- CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateDevice, 0);
- // Load vkDevice entry points
- #define VULKAN_DEVICE_FUNCTION(func) \
- renderer->func = (PFN_##func) \
- renderer->vkGetDeviceProcAddr( \
- renderer->logicalDevice, \
- #func);
- #include "SDL_gpu_vulkan_vkfuncs.h"
- renderer->vkGetDeviceQueue(
- renderer->logicalDevice,
- renderer->queueFamilyIndex,
- 0,
- &renderer->unifiedQueue);
- return 1;
- }
- static void VULKAN_INTERNAL_LoadEntryPoints(void)
- {
- // Required for MoltenVK support
- SDL_setenv_unsafe("MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE", "1", 1);
- // Load Vulkan entry points
- if (!SDL_Vulkan_LoadLibrary(NULL)) {
- SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Vulkan: SDL_Vulkan_LoadLibrary failed!");
- return;
- }
- #ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wpedantic"
- #endif
- vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr();
- #ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA
- #pragma GCC diagnostic pop
- #endif
- if (vkGetInstanceProcAddr == NULL) {
- SDL_LogWarn(
- SDL_LOG_CATEGORY_GPU,
- "SDL_Vulkan_GetVkGetInstanceProcAddr(): %s",
- SDL_GetError());
- return;
- }
- #define VULKAN_GLOBAL_FUNCTION(name) \
- name = (PFN_##name)vkGetInstanceProcAddr(VK_NULL_HANDLE, #name); \
- if (name == NULL) { \
- SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "vkGetInstanceProcAddr(VK_NULL_HANDLE, \"" #name "\") failed"); \
- return; \
- }
- #include "SDL_gpu_vulkan_vkfuncs.h"
- }
- static bool VULKAN_INTERNAL_PrepareVulkan(
- VulkanRenderer *renderer,
- VulkanFeatures *features,
- SDL_PropertiesID props)
- {
- VULKAN_INTERNAL_LoadEntryPoints();
- SDL_zerop(features);
- // Opt out device features (higher compatibility in exchange for reduced functionality)
- features->desiredVulkan10DeviceFeatures.samplerAnisotropy = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_ANISOTROPY_BOOLEAN, true) ? VK_TRUE : VK_FALSE;
- features->desiredVulkan10DeviceFeatures.depthClamp = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DEPTH_CLAMPING_BOOLEAN, true) ? VK_TRUE : VK_FALSE;
- features->desiredVulkan10DeviceFeatures.shaderClipDistance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_CLIP_DISTANCE_BOOLEAN, true) ? VK_TRUE : VK_FALSE;
- features->desiredVulkan10DeviceFeatures.drawIndirectFirstInstance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_INDIRECT_DRAW_FIRST_INSTANCE_BOOLEAN, true) ? VK_TRUE : VK_FALSE;
- // These features have near universal support so they are always enabled
- features->desiredVulkan10DeviceFeatures.independentBlend = VK_TRUE;
- features->desiredVulkan10DeviceFeatures.sampleRateShading = VK_TRUE;
- features->desiredVulkan10DeviceFeatures.imageCubeArray = VK_TRUE;
- // Handle opt-in device features
- VULKAN_INTERNAL_AddOptInVulkanOptions(props, renderer, features);
- renderer->requireHardwareAcceleration = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_REQUIRE_HARDWARE_ACCELERATION_BOOLEAN, false);
- if (!VULKAN_INTERNAL_CreateInstance(renderer, features)) {
- SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Vulkan: Could not create Vulkan instance");
- return false;
- }
- #define VULKAN_INSTANCE_FUNCTION(func) \
- renderer->func = (PFN_##func)vkGetInstanceProcAddr(renderer->instance, #func);
- #include "SDL_gpu_vulkan_vkfuncs.h"
- if (!VULKAN_INTERNAL_DeterminePhysicalDevice(renderer, features)) {
- SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Vulkan: Failed to determine a suitable physical device");
- return false;
- }
- return true;
- }
- static bool VULKAN_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props)
- {
- // Set up dummy VulkanRenderer
- VulkanRenderer *renderer;
- VulkanFeatures features;
- bool result = false;
- if (!SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN, false)) {
- return false;
- }
- if (_this->Vulkan_CreateSurface == NULL) {
- return false;
- }
- if (!SDL_Vulkan_LoadLibrary(NULL)) {
- return false;
- }
- renderer = (VulkanRenderer *)SDL_calloc(1, sizeof(*renderer));
- if (renderer) {
- // This needs to be set early for log filtering
- renderer->debugMode = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN, false);
- renderer->preferLowPower = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN, false);
- result = VULKAN_INTERNAL_PrepareVulkan(renderer, &features, props);
- if (result) {
- renderer->vkDestroyInstance(renderer->instance, NULL);
- }
- SDL_free(renderer);
- }
- SDL_Vulkan_UnloadLibrary();
- return result;
- }
- static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, SDL_PropertiesID props)
- {
- VulkanRenderer *renderer;
- VulkanFeatures features;
- SDL_GPUDevice *result;
- Uint32 i;
- bool verboseLogs = SDL_GetBooleanProperty(
- props,
- SDL_PROP_GPU_DEVICE_CREATE_VERBOSE_BOOLEAN,
- true);
- if (!SDL_Vulkan_LoadLibrary(NULL)) {
- SDL_assert(!"This should have failed in PrepareDevice first!");
- return NULL;
- }
- renderer = (VulkanRenderer *)SDL_calloc(1, sizeof(*renderer));
- if (!renderer) {
- SDL_Vulkan_UnloadLibrary();
- return NULL;
- }
- renderer->debugMode = debugMode;
- renderer->preferLowPower = preferLowPower;
- renderer->allowedFramesInFlight = 2;
- if (!VULKAN_INTERNAL_PrepareVulkan(renderer, &features, props)) {
- SET_STRING_ERROR("Failed to initialize Vulkan!");
- SDL_free(renderer);
- SDL_Vulkan_UnloadLibrary();
- return NULL;
- }
- renderer->props = SDL_CreateProperties();
- if (verboseLogs) {
- SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "SDL_GPU Driver: Vulkan");
- }
- // Record device name
- const char *deviceName = renderer->physicalDeviceProperties.properties.deviceName;
- SDL_SetStringProperty(
- renderer->props,
- SDL_PROP_GPU_DEVICE_NAME_STRING,
- deviceName);
- if (verboseLogs) {
- SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Vulkan Device: %s", deviceName);
- }
- // Record driver version. This is provided as a backup if
- // VK_KHR_driver_properties is not available but as most drivers support it
- // this property should be rarely used.
- //
- // This uses a vendor-specific encoding and it isn't well documented. The
- // vendor ID is the registered PCI ID of the vendor and can be found in
- // online databases.
- char driverVer[64];
- Uint32 rawDriverVer = renderer->physicalDeviceProperties.properties.driverVersion;
- Uint32 vendorId = renderer->physicalDeviceProperties.properties.vendorID;
- if (vendorId == 0x10de) {
- // Nvidia uses 10|8|8|6 encoding.
- (void)SDL_snprintf(
- driverVer,
- SDL_arraysize(driverVer),
- "%d.%d.%d.%d",
- (rawDriverVer >> 22) & 0x3ff,
- (rawDriverVer >> 14) & 0xff,
- (rawDriverVer >> 6) & 0xff,
- rawDriverVer & 0x3f);
- }
- #ifdef SDL_PLATFORM_WINDOWS
- else if (vendorId == 0x8086) {
- // Intel uses 18|14 encoding on Windows only.
- (void)SDL_snprintf(
- driverVer,
- SDL_arraysize(driverVer),
- "%d.%d",
- (rawDriverVer >> 14) & 0x3ffff,
- rawDriverVer & 0x3fff);
- }
- #endif
- else {
- // Assume standard Vulkan 10|10|12 encoding for everything else. AMD and
- // Mesa are known to use this encoding.
- (void)SDL_snprintf(
- driverVer,
- SDL_arraysize(driverVer),
- "%d.%d.%d",
- (rawDriverVer >> 22) & 0x3ff,
- (rawDriverVer >> 12) & 0x3ff,
- rawDriverVer & 0xfff);
- }
- SDL_SetStringProperty(
- renderer->props,
- SDL_PROP_GPU_DEVICE_DRIVER_VERSION_STRING,
- driverVer);
- // Log this only if VK_KHR_driver_properties is not available.
- if (renderer->supports.KHR_driver_properties) {
- // Record driver name and version
- const char *driverName = renderer->physicalDeviceDriverProperties.driverName;
- const char *driverInfo = renderer->physicalDeviceDriverProperties.driverInfo;
- SDL_SetStringProperty(
- renderer->props,
- SDL_PROP_GPU_DEVICE_DRIVER_NAME_STRING,
- driverName);
- SDL_SetStringProperty(
- renderer->props,
- SDL_PROP_GPU_DEVICE_DRIVER_INFO_STRING,
- driverInfo);
- if (verboseLogs) {
- // FIXME: driverInfo can be a multiline string.
- SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Vulkan Driver: %s %s", driverName, driverInfo);
- }
- // Record conformance level
- if (verboseLogs) {
- char conformance[64];
- (void)SDL_snprintf(
- conformance,
- SDL_arraysize(conformance),
- "%u.%u.%u.%u",
- renderer->physicalDeviceDriverProperties.conformanceVersion.major,
- renderer->physicalDeviceDriverProperties.conformanceVersion.minor,
- renderer->physicalDeviceDriverProperties.conformanceVersion.subminor,
- renderer->physicalDeviceDriverProperties.conformanceVersion.patch);
- SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Vulkan Conformance: %s", conformance);
- }
- } else {
- if (verboseLogs) {
- SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Vulkan Driver: %s", driverVer);
- }
- }
- if (!VULKAN_INTERNAL_CreateLogicalDevice(renderer, &features)) {
- SET_STRING_ERROR("Failed to create logical device!");
- SDL_free(renderer);
- SDL_Vulkan_UnloadLibrary();
- return NULL;
- }
- // FIXME: just move this into this function
- result = (SDL_GPUDevice *)SDL_calloc(1, sizeof(SDL_GPUDevice));
- ASSIGN_DRIVER(VULKAN)
- result->driverData = (SDL_GPURenderer *)renderer;
- result->shader_formats = SDL_GPU_SHADERFORMAT_SPIRV;
- /*
- * Create initial swapchain array
- */
- renderer->claimedWindowCapacity = 1;
- renderer->claimedWindowCount = 0;
- renderer->claimedWindows = SDL_malloc(
- renderer->claimedWindowCapacity * sizeof(WindowData *));
- // Threading
- renderer->allocatorLock = SDL_CreateMutex();
- renderer->disposeLock = SDL_CreateMutex();
- renderer->submitLock = SDL_CreateMutex();
- renderer->acquireCommandBufferLock = SDL_CreateMutex();
- renderer->acquireUniformBufferLock = SDL_CreateMutex();
- renderer->renderPassFetchLock = SDL_CreateMutex();
- renderer->framebufferFetchLock = SDL_CreateMutex();
- renderer->graphicsPipelineLayoutFetchLock = SDL_CreateMutex();
- renderer->computePipelineLayoutFetchLock = SDL_CreateMutex();
- renderer->descriptorSetLayoutFetchLock = SDL_CreateMutex();
- renderer->windowLock = SDL_CreateMutex();
- /*
- * Create submitted command buffer list
- */
- renderer->submittedCommandBufferCapacity = 16;
- renderer->submittedCommandBufferCount = 0;
- renderer->submittedCommandBuffers = SDL_malloc(sizeof(VulkanCommandBuffer *) * renderer->submittedCommandBufferCapacity);
- // Memory Allocator
- renderer->memoryAllocator = (VulkanMemoryAllocator *)SDL_malloc(
- sizeof(VulkanMemoryAllocator));
- for (i = 0; i < VK_MAX_MEMORY_TYPES; i += 1) {
- renderer->memoryAllocator->subAllocators[i].memoryTypeIndex = i;
- renderer->memoryAllocator->subAllocators[i].allocations = NULL;
- renderer->memoryAllocator->subAllocators[i].allocationCount = 0;
- renderer->memoryAllocator->subAllocators[i].sortedFreeRegions = SDL_malloc(
- sizeof(VulkanMemoryFreeRegion *) * 4);
- renderer->memoryAllocator->subAllocators[i].sortedFreeRegionCount = 0;
- renderer->memoryAllocator->subAllocators[i].sortedFreeRegionCapacity = 4;
- }
- // Create uniform buffer pool
- renderer->uniformBufferPoolCount = 32;
- renderer->uniformBufferPoolCapacity = 32;
- renderer->uniformBufferPool = SDL_malloc(
- renderer->uniformBufferPoolCapacity * sizeof(VulkanUniformBuffer *));
- for (i = 0; i < renderer->uniformBufferPoolCount; i += 1) {
- renderer->uniformBufferPool[i] = VULKAN_INTERNAL_CreateUniformBuffer(
- renderer,
- UNIFORM_BUFFER_SIZE);
- }
- renderer->descriptorSetCachePoolCapacity = 8;
- renderer->descriptorSetCachePoolCount = 0;
- renderer->descriptorSetCachePool = SDL_calloc(renderer->descriptorSetCachePoolCapacity, sizeof(DescriptorSetCache *));
- SDL_SetAtomicInt(&renderer->layoutResourceID, 0);
- // Device limits
- renderer->minUBOAlignment = (Uint32)renderer->physicalDeviceProperties.properties.limits.minUniformBufferOffsetAlignment;
- // Initialize caches
- renderer->commandPoolHashTable = SDL_CreateHashTable(
- 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful.
- false, // manually synchronized due to submission timing
- VULKAN_INTERNAL_CommandPoolHashFunction,
- VULKAN_INTERNAL_CommandPoolHashKeyMatch,
- VULKAN_INTERNAL_CommandPoolHashDestroy,
- (void *)renderer);
- renderer->renderPassHashTable = SDL_CreateHashTable(
- 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful.
- false, // manually synchronized due to lookup timing
- VULKAN_INTERNAL_RenderPassHashFunction,
- VULKAN_INTERNAL_RenderPassHashKeyMatch,
- VULKAN_INTERNAL_RenderPassHashDestroy,
- (void *)renderer);
- renderer->framebufferHashTable = SDL_CreateHashTable(
- 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful.
- false, // manually synchronized due to iteration
- VULKAN_INTERNAL_FramebufferHashFunction,
- VULKAN_INTERNAL_FramebufferHashKeyMatch,
- VULKAN_INTERNAL_FramebufferHashDestroy,
- (void *)renderer);
- renderer->graphicsPipelineResourceLayoutHashTable = SDL_CreateHashTable(
- 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful.
- false, // manually synchronized due to lookup timing
- VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashFunction,
- VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashKeyMatch,
- VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashDestroy,
- (void *)renderer);
- renderer->computePipelineResourceLayoutHashTable = SDL_CreateHashTable(
- 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful.
- false, // manually synchronized due to lookup timing
- VULKAN_INTERNAL_ComputePipelineResourceLayoutHashFunction,
- VULKAN_INTERNAL_ComputePipelineResourceLayoutHashKeyMatch,
- VULKAN_INTERNAL_ComputePipelineResourceLayoutHashDestroy,
- (void *)renderer);
- renderer->descriptorSetLayoutHashTable = SDL_CreateHashTable(
- 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful.
- false, // manually synchronized due to lookup timing
- VULKAN_INTERNAL_DescriptorSetLayoutHashFunction,
- VULKAN_INTERNAL_DescriptorSetLayoutHashKeyMatch,
- VULKAN_INTERNAL_DescriptorSetLayoutHashDestroy,
- (void *)renderer);
- // Initialize fence pool
- renderer->fencePool.lock = SDL_CreateMutex();
- renderer->fencePool.availableFenceCapacity = 4;
- renderer->fencePool.availableFenceCount = 0;
- renderer->fencePool.availableFences = SDL_malloc(
- renderer->fencePool.availableFenceCapacity * sizeof(VulkanFenceHandle *));
- // Deferred destroy storage
- renderer->texturesToDestroyCapacity = 16;
- renderer->texturesToDestroyCount = 0;
- renderer->texturesToDestroy = (VulkanTexture **)SDL_malloc(
- sizeof(VulkanTexture *) *
- renderer->texturesToDestroyCapacity);
- renderer->buffersToDestroyCapacity = 16;
- renderer->buffersToDestroyCount = 0;
- renderer->buffersToDestroy = SDL_malloc(
- sizeof(VulkanBuffer *) *
- renderer->buffersToDestroyCapacity);
- renderer->samplersToDestroyCapacity = 16;
- renderer->samplersToDestroyCount = 0;
- renderer->samplersToDestroy = SDL_malloc(
- sizeof(VulkanSampler *) *
- renderer->samplersToDestroyCapacity);
- renderer->graphicsPipelinesToDestroyCapacity = 16;
- renderer->graphicsPipelinesToDestroyCount = 0;
- renderer->graphicsPipelinesToDestroy = SDL_malloc(
- sizeof(VulkanGraphicsPipeline *) *
- renderer->graphicsPipelinesToDestroyCapacity);
- renderer->computePipelinesToDestroyCapacity = 16;
- renderer->computePipelinesToDestroyCount = 0;
- renderer->computePipelinesToDestroy = SDL_malloc(
- sizeof(VulkanComputePipeline *) *
- renderer->computePipelinesToDestroyCapacity);
- renderer->shadersToDestroyCapacity = 16;
- renderer->shadersToDestroyCount = 0;
- renderer->shadersToDestroy = SDL_malloc(
- sizeof(VulkanShader *) *
- renderer->shadersToDestroyCapacity);
- renderer->framebuffersToDestroyCapacity = 16;
- renderer->framebuffersToDestroyCount = 0;
- renderer->framebuffersToDestroy = SDL_malloc(
- sizeof(VulkanFramebuffer *) *
- renderer->framebuffersToDestroyCapacity);
- // Defrag state
- renderer->defragInProgress = 0;
- renderer->allocationsToDefragCount = 0;
- renderer->allocationsToDefragCapacity = 4;
- renderer->allocationsToDefrag = SDL_malloc(
- renderer->allocationsToDefragCapacity * sizeof(VulkanMemoryAllocation *));
- return result;
- }
- SDL_GPUBootstrap VulkanDriver = {
- "vulkan",
- VULKAN_PrepareDriver,
- VULKAN_CreateDevice
- };
- #endif // SDL_GPU_VULKAN
|