| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541 |
- /*
- 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"
- #ifdef HAVE_GPU_OPENXR
- #define XR_USE_GRAPHICS_API_VULKAN 1
- #include "../xr/SDL_openxr_internal.h"
- #include "../xr/SDL_openxrdyn.h"
- #include "../xr/SDL_gpu_openxr.h"
- #endif
- #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.internal.gpu.vulkan.data"
- #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
- };
- // NOTE: this is behind an ifdef guard because without, it would trigger an "unused variable" error when OpenXR support is disabled
- #ifdef HAVE_GPU_OPENXR
- typedef struct TextureFormatPair {
- VkFormat vk;
- SDL_GPUTextureFormat sdl;
- } TextureFormatPair;
- static TextureFormatPair SDLToVK_TextureFormat_SrgbOnly[] = {
- {VK_FORMAT_R8G8B8A8_SRGB, SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB},
- {VK_FORMAT_B8G8R8A8_SRGB, SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB},
- {VK_FORMAT_BC1_RGBA_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM_SRGB},
- {VK_FORMAT_BC2_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM_SRGB},
- {VK_FORMAT_BC3_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM_SRGB},
- {VK_FORMAT_BC7_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM_SRGB},
- {VK_FORMAT_ASTC_4x4_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_4x4_UNORM_SRGB},
- {VK_FORMAT_ASTC_5x4_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_5x4_UNORM_SRGB},
- {VK_FORMAT_ASTC_5x5_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_5x5_UNORM_SRGB},
- {VK_FORMAT_ASTC_6x5_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_6x5_UNORM_SRGB},
- {VK_FORMAT_ASTC_6x6_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_6x6_UNORM_SRGB},
- {VK_FORMAT_ASTC_8x5_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_8x5_UNORM_SRGB},
- {VK_FORMAT_ASTC_8x6_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_8x6_UNORM_SRGB},
- {VK_FORMAT_ASTC_8x8_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_8x8_UNORM_SRGB},
- {VK_FORMAT_ASTC_10x5_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_10x5_UNORM_SRGB},
- {VK_FORMAT_ASTC_10x6_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_10x6_UNORM_SRGB},
- {VK_FORMAT_ASTC_10x8_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_10x8_UNORM_SRGB},
- {VK_FORMAT_ASTC_10x10_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_10x10_UNORM_SRGB},
- {VK_FORMAT_ASTC_12x10_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_12x10_UNORM_SRGB},
- {VK_FORMAT_ASTC_12x12_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_12x12_UNORM_SRGB},
- };
- #endif // HAVE_GPU_OPENXR
- 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 VulkanRenderer VulkanRenderer;
- typedef struct VulkanCommandPool VulkanCommandPool;
- 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
- bool externallyManaged; // true for XR swapchain images
- SDL_AtomicInt referenceCount;
- };
- struct VulkanTextureContainer
- {
- TextureCommonHeader header;
- VulkanTexture *activeTexture;
- Uint32 textureCapacity;
- Uint32 textureCount;
- VulkanTexture **textures;
- char *debugName;
- bool canBeCycled;
- bool externallyManaged; // true for XR swapchain images
- };
- 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;
- VulkanRenderer *renderer;
- int refcount;
- 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 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;
- // OpenXR
- Uint32 minimumVkVersion;
- #ifdef HAVE_GPU_OPENXR
- XrInstance xrInstance; // a non-null instance also states this vk device was created by OpenXR
- XrSystemId xrSystemId;
- XrInstancePfns *xr;
- #endif
- 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);
- }
- /* Don't free an externally managed VkImage (e.g. XR swapchain images) */
- if (texture->image && !texture->externallyManaged) {
- 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 = (WindowData *)SDL_calloc(1, sizeof(WindowData));
- if (!windowData) {
- return false;
- }
- windowData->window = window;
- windowData->renderer = renderer;
- windowData->refcount = 1;
- 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_free(windowData);
- return SDL_SetError("No video device found");
- }
- if (!videoDevice->Vulkan_CreateSurface) {
- SDL_free(windowData);
- return SDL_SetError("Video device does not implement Vulkan_CreateSurface");
- }
- // Each window must have its own surface.
- if (!videoDevice->Vulkan_CreateSurface(
- videoDevice,
- windowData->window,
- renderer->instance,
- NULL, // FIXME: VAllocationCallbacks
- &windowData->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 if (windowData->renderer == renderer) {
- ++windowData->refcount;
- return true;
- } 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;
- }
- if (windowData->renderer != renderer) {
- SDL_SetError("Window not claimed by this device");
- return;
- }
- if (windowData->refcount > 1) {
- --windowData->refcount;
- 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;
- }
- #ifdef HAVE_GPU_OPENXR
- if (renderer->xrInstance) {
- XrResult xrResult;
- PFN_xrCreateVulkanInstanceKHR xrCreateVulkanInstanceKHR;
- if ((xrResult = xrGetInstanceProcAddr(renderer->xrInstance, "xrCreateVulkanInstanceKHR", (PFN_xrVoidFunction *)&xrCreateVulkanInstanceKHR)) != XR_SUCCESS) {
- SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get xrCreateVulkanInstanceKHR");
- SDL_stack_free((char *)instanceExtensionNames);
- return 0;
- }
- XrVulkanInstanceCreateInfoKHR xrCreateInfo = {};
- xrCreateInfo.type = XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR;
- xrCreateInfo.vulkanCreateInfo = &createInfo;
- xrCreateInfo.systemId = renderer->xrSystemId;
- xrCreateInfo.pfnGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr();
- SDL_assert(xrCreateInfo.pfnGetInstanceProcAddr);
- if ((xrResult = xrCreateVulkanInstanceKHR(renderer->xrInstance, &xrCreateInfo, &renderer->instance, &vulkanResult)) != XR_SUCCESS) {
- SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to create vulkan instance, reason %d, %d", xrResult, vulkanResult);
- SDL_stack_free((char *)instanceExtensionNames);
- return 0;
- }
- } else
- #endif // HAVE_GPU_OPENXR
- {
- 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;
- bool isConformant;
- VkPhysicalDeviceType deviceType;
- if (physicalDeviceExtensions->KHR_driver_properties || physicalDeviceExtensions->MSFT_layered_driver) {
- VkPhysicalDeviceProperties2KHR physicalDeviceProperties;
- VkPhysicalDeviceDriverPropertiesKHR physicalDeviceDriverProperties = { 0 };
- VkPhysicalDeviceLayeredDriverPropertiesMSFT physicalDeviceLayeredDriverProperties = { 0 };
- void** ppNext = &physicalDeviceProperties.pNext;
- physicalDeviceProperties.sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
- if (physicalDeviceExtensions->KHR_driver_properties) {
- *ppNext = &physicalDeviceDriverProperties;
- ppNext = &physicalDeviceDriverProperties.pNext;
- physicalDeviceDriverProperties.sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR;
- }
- if (physicalDeviceExtensions->MSFT_layered_driver) {
- *ppNext = &physicalDeviceLayeredDriverProperties;
- ppNext = &physicalDeviceLayeredDriverProperties.pNext;
- physicalDeviceLayeredDriverProperties.sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_DRIVER_PROPERTIES_MSFT;
- }
- *ppNext = NULL;
- renderer->vkGetPhysicalDeviceProperties2KHR(
- physicalDevice,
- &physicalDeviceProperties);
- if (physicalDeviceExtensions->KHR_driver_properties) {
- isConformant = (physicalDeviceDriverProperties.conformanceVersion.major >= 1);
- } else {
- isConformant = true; // We can't check this, so just assume it's conformant
- }
- if (physicalDeviceExtensions->MSFT_layered_driver && physicalDeviceLayeredDriverProperties.underlyingAPI != VK_LAYERED_DRIVER_UNDERLYING_API_NONE_MSFT) {
- /* Rank Dozen above CPU, but below INTEGRATED.
- * This is needed for WSL specifically.
- */
- deviceType = VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU;
- /* Dozen hasn't been tested for conformance and it probably won't be,
- * but WSL may need this so let's be generous.
- * -flibit
- */
- isConformant = true;
- } else {
- deviceType = physicalDeviceProperties.properties.deviceType;
- }
- } else {
- VkPhysicalDeviceProperties physicalDeviceProperties;
- renderer->vkGetPhysicalDeviceProperties(
- physicalDevice,
- &physicalDeviceProperties);
- deviceType = physicalDeviceProperties.deviceType;
- isConformant = true; // We can't check this, so just assume it's conformant
- }
- 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;
- }
- }
- /* As far as I know, the only drivers available to users that are also
- * non-conformant are incomplete Mesa drivers and Vulkan-on-12. hasvk is one
- * example of a non-conformant driver that's built by default.
- * -flibit
- */
- if (!isConformant) {
- 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;
- #ifdef HAVE_GPU_OPENXR
- // When XR is enabled, let the OpenXR runtime choose the physical device
- if (renderer->xrInstance) {
- XrResult xrResult;
- VulkanExtensions xrPhysicalDeviceExtensions;
- Uint32 queueFamilyIndex;
- PFN_xrGetVulkanGraphicsDevice2KHR xrGetVulkanGraphicsDevice2KHR;
- xrResult = xrGetInstanceProcAddr(
- renderer->xrInstance,
- "xrGetVulkanGraphicsDevice2KHR",
- (PFN_xrVoidFunction *)&xrGetVulkanGraphicsDevice2KHR);
- if (xrResult != XR_SUCCESS) {
- SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to get xrGetVulkanGraphicsDevice2KHR, result: %d", xrResult);
- return 0;
- }
- XrVulkanGraphicsDeviceGetInfoKHR graphicsDeviceGetInfo;
- SDL_zero(graphicsDeviceGetInfo);
- graphicsDeviceGetInfo.type = XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR;
- graphicsDeviceGetInfo.systemId = renderer->xrSystemId;
- graphicsDeviceGetInfo.vulkanInstance = renderer->instance;
- xrResult = xrGetVulkanGraphicsDevice2KHR(
- renderer->xrInstance,
- &graphicsDeviceGetInfo,
- &renderer->physicalDevice);
- if (xrResult != XR_SUCCESS) {
- SDL_LogError(SDL_LOG_CATEGORY_GPU, "xrGetVulkanGraphicsDevice2KHR failed, result: %d", xrResult);
- return 0;
- }
- // Verify the XR-chosen device is suitable
- if (!VULKAN_INTERNAL_IsDeviceSuitable(
- renderer,
- features,
- renderer->physicalDevice,
- &xrPhysicalDeviceExtensions,
- &queueFamilyIndex)) {
- SDL_LogError(SDL_LOG_CATEGORY_GPU, "The physical device chosen by the OpenXR runtime is not suitable");
- return 0;
- }
- renderer->supports = xrPhysicalDeviceExtensions;
- renderer->queueFamilyIndex = queueFamilyIndex;
- } else
- #endif // HAVE_GPU_OPENXR
- {
- 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;
- }
- SDL_stack_free(physicalDevices);
- SDL_stack_free(physicalDeviceExtensions);
- }
- 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);
- } else {
- renderer->physicalDeviceProperties.pNext = NULL;
- renderer->vkGetPhysicalDeviceProperties(
- renderer->physicalDevice,
- &renderer->physicalDeviceProperties.properties);
- }
- renderer->vkGetPhysicalDeviceMemoryProperties(
- renderer->physicalDevice,
- &renderer->memoryProperties);
- 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;
- }
- #ifdef HAVE_GPU_OPENXR
- if (renderer->xrInstance) {
- XrResult xrResult;
- PFN_xrCreateVulkanDeviceKHR xrCreateVulkanDeviceKHR;
- if ((xrResult = xrGetInstanceProcAddr(renderer->xrInstance, "xrCreateVulkanDeviceKHR", (PFN_xrVoidFunction *)&xrCreateVulkanDeviceKHR)) != XR_SUCCESS) {
- SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get xrCreateVulkanDeviceKHR");
- SDL_stack_free((void *)deviceExtensions);
- return 0;
- }
- XrVulkanDeviceCreateInfoKHR xrDeviceCreateInfo = {};
- xrDeviceCreateInfo.type = XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR;
- xrDeviceCreateInfo.vulkanCreateInfo = &deviceCreateInfo;
- xrDeviceCreateInfo.systemId = renderer->xrSystemId;
- xrDeviceCreateInfo.vulkanPhysicalDevice = renderer->physicalDevice;
- xrDeviceCreateInfo.pfnGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr();
- SDL_assert(xrDeviceCreateInfo.pfnGetInstanceProcAddr);
- if ((xrResult = xrCreateVulkanDeviceKHR(renderer->xrInstance, &xrDeviceCreateInfo, &renderer->logicalDevice, &vulkanResult)) != XR_SUCCESS) {
- SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create OpenXR Vulkan logical device, result %d, %d", xrResult, vulkanResult);
- SDL_stack_free((void *)deviceExtensions);
- return 0;
- }
- } else
- #endif // HAVE_GPU_OPENXR
- {
- 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;
- }
- #ifdef HAVE_GPU_OPENXR
- static bool VULKAN_INTERNAL_SearchForOpenXrGpuExtension(XrExtensionProperties *found_extension)
- {
- XrResult result;
- Uint32 extension_count;
- Uint32 i;
- result = xrEnumerateInstanceExtensionProperties(NULL, 0, &extension_count, NULL);
- if (result != XR_SUCCESS)
- return false;
- XrExtensionProperties *extension_properties = (XrExtensionProperties *)SDL_calloc(extension_count, sizeof(XrExtensionProperties));
- for (i = 0; i < extension_count; i++)
- extension_properties[i].type = XR_TYPE_EXTENSION_PROPERTIES;
- result = xrEnumerateInstanceExtensionProperties(NULL, extension_count, &extension_count, extension_properties);
- if (result != XR_SUCCESS) {
- SDL_free(extension_properties);
- return false;
- }
- for (i = 0; i < extension_count; i++) {
- XrExtensionProperties extension = extension_properties[i];
- // NOTE: as generally recommended, we support KHR_vulkan_enable2 *only*
- // see https://fredemmott.com/blog/2024/11/25/best-practices-for-openxr-api-layers.html
- if (SDL_strcmp(extension.extensionName, XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME) == 0) {
- SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Found " XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME " extension");
- *found_extension = extension;
- SDL_free(extension_properties);
- return true;
- }
- }
- SDL_free(extension_properties);
- return false;
- }
- static XrResult VULKAN_INTERNAL_GetXrMinimumVulkanApiVersion(XrVersion *minimumVulkanApiVersion, XrInstance instance, XrSystemId systemId)
- {
- XrResult xrResult;
- PFN_xrGetVulkanGraphicsRequirements2KHR xrGetVulkanGraphicsRequirements2KHR;
- if ((xrResult = xrGetInstanceProcAddr(instance, "xrGetVulkanGraphicsRequirements2KHR", (PFN_xrVoidFunction *)&xrGetVulkanGraphicsRequirements2KHR)) != XR_SUCCESS) {
- SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get xrGetVulkanGraphicsRequirements2KHR");
- return xrResult;
- }
- XrGraphicsRequirementsVulkanKHR graphicsRequirementsVulkan = {};
- graphicsRequirementsVulkan.type = XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN2_KHR;
- if ((xrResult = xrGetVulkanGraphicsRequirements2KHR(instance, systemId, &graphicsRequirementsVulkan)) != XR_SUCCESS) {
- SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get vulkan graphics requirements, got OpenXR error %d", xrResult);
- return xrResult;
- }
- *minimumVulkanApiVersion = graphicsRequirementsVulkan.minApiVersionSupported;
- return XR_SUCCESS;
- }
- #endif // HAVE_GPU_OPENXR
- 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;
- }
- #ifdef HAVE_GPU_OPENXR
- XrResult xrResult;
- XrInstancePfns *instancePfns = NULL;
- XrInstance xrInstance = XR_NULL_HANDLE;
- XrSystemId xrSystemId = XR_NULL_HANDLE;
- bool xr = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_ENABLE_BOOLEAN, false);
- #ifdef SDL_PLATFORM_ANDROID
- /* On Android/Quest, don't test XR in PrepareDriver. The Quest OpenXR runtime
- * can't handle having its instance created and destroyed during preparation
- * and then recreated during device creation. Just return true for XR mode
- * and let CreateDevice do the real work. */
- if (xr) {
- SDL_Vulkan_UnloadLibrary();
- return true;
- }
- #endif
- if (xr) {
- if (!SDL_OpenXR_LoadLibrary()) {
- /* SDL_GetError() already has the detailed message from SDL_OpenXR_LoadLibrary() */
- SDL_Vulkan_UnloadLibrary();
- return false;
- }
- XrExtensionProperties gpuExtension;
- if (!VULKAN_INTERNAL_SearchForOpenXrGpuExtension(&gpuExtension)) {
- SDL_SetError("Failed to find a suitable OpenXR GPU extension.");
- SDL_Vulkan_UnloadLibrary();
- SDL_OpenXR_UnloadLibrary();
- return false;
- }
- const char *extensionName = gpuExtension.extensionName;
- if ((xrResult = xrCreateInstance(&(XrInstanceCreateInfo){
- .type = XR_TYPE_INSTANCE_CREATE_INFO,
- .applicationInfo = {
- .apiVersion = SDL_GetNumberProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_VERSION_NUMBER, XR_API_VERSION_1_0),
- .applicationName = "SDL",
- },
- .enabledExtensionCount = 1,
- .enabledExtensionNames = &extensionName,
- },
- &xrInstance)) != XR_SUCCESS) {
- SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to create OpenXR instance");
- SDL_Vulkan_UnloadLibrary();
- SDL_OpenXR_UnloadLibrary();
- return false;
- }
- instancePfns = SDL_OPENXR_LoadInstanceSymbols(xrInstance);
- if (!instancePfns) {
- SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to load needed OpenXR instance symbols");
- SDL_Vulkan_UnloadLibrary();
- SDL_OpenXR_UnloadLibrary();
- return false;
- }
- if ((xrResult = instancePfns->xrGetSystem(xrInstance, &(XrSystemGetInfo){
- .type = XR_TYPE_SYSTEM_GET_INFO,
- .formFactor = (XrFormFactor)SDL_GetNumberProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_FORM_FACTOR_NUMBER, XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY),
- },
- &xrSystemId)) != XR_SUCCESS) {
- SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get OpenXR system");
- instancePfns->xrDestroyInstance(xrInstance);
- SDL_Vulkan_UnloadLibrary();
- SDL_OpenXR_UnloadLibrary();
- SDL_free(instancePfns);
- return false;
- }
- }
- #endif // HAVE_GPU_OPENXR
- 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);
- renderer->minimumVkVersion = VK_API_VERSION_1_0;
- #ifdef HAVE_GPU_OPENXR
- renderer->xrInstance = xrInstance;
- renderer->xrSystemId = xrSystemId;
- if (xr) {
- XrVersion minimumVkVersionXr;
- xrResult = VULKAN_INTERNAL_GetXrMinimumVulkanApiVersion(&minimumVkVersionXr, xrInstance, xrSystemId);
- if (xrResult != XR_SUCCESS) {
- SDL_SetError("Failed to get the minimum supported Vulkan API version.");
- instancePfns->xrDestroyInstance(xrInstance);
- SDL_Vulkan_UnloadLibrary();
- SDL_OpenXR_UnloadLibrary();
- SDL_free(instancePfns);
- SDL_free(renderer);
- return false;
- }
- renderer->minimumVkVersion = VK_MAKE_API_VERSION(
- 0,
- XR_VERSION_MAJOR(minimumVkVersionXr),
- XR_VERSION_MINOR(minimumVkVersionXr),
- XR_VERSION_PATCH(minimumVkVersionXr));
- }
- #endif // HAVE_GPU_OPENXR
- result = VULKAN_INTERNAL_PrepareVulkan(renderer, &features, props);
- if (result) {
- renderer->vkDestroyInstance(renderer->instance, NULL);
- }
- #ifdef HAVE_GPU_OPENXR
- if (instancePfns) {
- instancePfns->xrDestroyInstance(xrInstance);
- SDL_free(instancePfns);
- SDL_OpenXR_UnloadLibrary();
- }
- #endif // HAVE_GPU_OPENXR
- SDL_free(renderer);
- }
- SDL_Vulkan_UnloadLibrary();
- return result;
- }
- static XrResult VULKAN_DestroyXRSwapchain(
- SDL_GPURenderer *driverData,
- XrSwapchain swapchain,
- SDL_GPUTexture **swapchainImages)
- {
- #ifdef HAVE_GPU_OPENXR
- XrResult result;
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- VULKAN_Wait(driverData);
- Uint32 swapchainCount;
- result = renderer->xr->xrEnumerateSwapchainImages(swapchain, 0, &swapchainCount, NULL);
- if (result != XR_SUCCESS) {
- return result;
- }
- // We always want to destroy the swapchain images, so don't early return if xrDestroySwapchain fails for some reason
- for (Uint32 i = 0; i < swapchainCount; i++) {
- VulkanTextureContainer *container = (VulkanTextureContainer *)swapchainImages[i];
- if (!container->externallyManaged) {
- SDL_SetError("Invalid GPU Texture handle.");
- return XR_ERROR_HANDLE_INVALID;
- }
- VULKAN_INTERNAL_DestroyTexture(renderer, container->activeTexture);
- // Free the container now that it's unused
- SDL_free(container);
- }
- SDL_free(swapchainImages);
- return renderer->xr->xrDestroySwapchain(swapchain);
- #else
- SDL_SetError("SDL not built with OpenXR support");
- return XR_ERROR_FUNCTION_UNSUPPORTED;
- #endif
- }
- #ifdef HAVE_GPU_OPENXR
- static bool VULKAN_INTERNAL_FindXRSrgbSwapchain(int64_t *supportedFormats, Uint32 numFormats, SDL_GPUTextureFormat *sdlFormat, int64_t *vkFormat)
- {
- for (Uint32 i = 0; i < SDL_arraysize(SDLToVK_TextureFormat_SrgbOnly); i++) {
- for (Uint32 j = 0; j < numFormats; j++) {
- if (SDLToVK_TextureFormat_SrgbOnly[i].vk == supportedFormats[j]) {
- *sdlFormat = SDLToVK_TextureFormat_SrgbOnly[i].sdl;
- *vkFormat = SDLToVK_TextureFormat_SrgbOnly[i].vk;
- return true;
- }
- }
- }
- return false;
- }
- #endif // HAVE_GPU_OPENXR
- static SDL_GPUTextureFormat* VULKAN_GetXRSwapchainFormats(
- SDL_GPURenderer *driverData,
- XrSession session,
- int *num_formats)
- {
- #ifdef HAVE_GPU_OPENXR
- XrResult result;
- Uint32 i, j, num_supported_formats;
- int64_t *supported_formats;
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- result = renderer->xr->xrEnumerateSwapchainFormats(session, 0, &num_supported_formats, NULL);
- if (result != XR_SUCCESS) return NULL;
- supported_formats = SDL_stack_alloc(int64_t, num_supported_formats);
- result = renderer->xr->xrEnumerateSwapchainFormats(session, num_supported_formats, &num_supported_formats, supported_formats);
- if (result != XR_SUCCESS) {
- SDL_stack_free(supported_formats);
- return NULL;
- }
- // FIXME: For now we're just searching for the optimal format, not all supported formats.
- // FIXME: Expand this search for all SDL_GPU formats!
- SDL_GPUTextureFormat sdlFormat = SDL_GPU_TEXTUREFORMAT_INVALID;
- int64_t vkFormat = VK_FORMAT_UNDEFINED;
- // The OpenXR spec recommends applications not submit linear data, so let's try to explicitly find an sRGB swapchain before we search the whole list
- if (!VULKAN_INTERNAL_FindXRSrgbSwapchain(supported_formats, num_supported_formats, &sdlFormat, &vkFormat)) {
- // Iterate over all formats the runtime supports
- for (i = 0; i < num_supported_formats && vkFormat == VK_FORMAT_UNDEFINED; i++) {
- // Iterate over all formats we support
- for (j = 0; j < SDL_arraysize(SDLToVK_TextureFormat); j++) {
- // Pick the first format the runtime wants that we also support, the runtime should return these in order of preference
- if (SDLToVK_TextureFormat[j] == supported_formats[i]) {
- vkFormat = supported_formats[i];
- sdlFormat = j;
- break;
- }
- }
- }
- }
- SDL_stack_free(supported_formats);
- if (vkFormat == VK_FORMAT_UNDEFINED) {
- SDL_SetError("Failed to find a swapchain format supported by both OpenXR and SDL");
- return NULL;
- }
- SDL_GPUTextureFormat *retval = (SDL_GPUTextureFormat*) SDL_malloc(sizeof(SDL_GPUTextureFormat) * 2);
- retval[0] = sdlFormat;
- retval[1] = SDL_GPU_TEXTUREFORMAT_INVALID;
- *num_formats = 1;
- return retval;
- #else
- SDL_SetError("SDL not built with OpenXR support");
- return NULL;
- #endif
- }
- static XrResult VULKAN_CreateXRSwapchain(
- SDL_GPURenderer *driverData,
- XrSession session,
- const XrSwapchainCreateInfo *oldCreateInfo,
- SDL_GPUTextureFormat format,
- XrSwapchain *swapchain,
- SDL_GPUTexture ***textures)
- {
- #ifdef HAVE_GPU_OPENXR
- XrResult result;
- Uint32 i, j;
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- XrSwapchainCreateInfo createInfo = *oldCreateInfo;
- createInfo.format = SDLToVK_TextureFormat[format];
- result = renderer->xr->xrCreateSwapchain(session, &createInfo, swapchain);
- if (result != XR_SUCCESS) return result;
- Uint32 swapchainImageCount;
- result = renderer->xr->xrEnumerateSwapchainImages(*swapchain, 0, &swapchainImageCount, NULL);
- if (result != XR_SUCCESS) return result;
- XrSwapchainImageVulkan2KHR *swapchainImages = (XrSwapchainImageVulkan2KHR *)SDL_calloc(swapchainImageCount, sizeof(XrSwapchainImageVulkan2KHR));
- for (i = 0; i < swapchainImageCount; i++) swapchainImages[i].type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN2_KHR;
- result = renderer->xr->xrEnumerateSwapchainImages(*swapchain, swapchainImageCount, &swapchainImageCount, (XrSwapchainImageBaseHeader *)swapchainImages);
- if (result != XR_SUCCESS) {
- SDL_free(swapchainImages);
- return result;
- }
- VulkanTextureContainer **textureContainers = (VulkanTextureContainer **)SDL_calloc(swapchainImageCount, sizeof(VulkanTextureContainer *));
- for (Uint32 idx = 0; idx < swapchainImageCount; idx++) {
- VkImage vkImage = swapchainImages[idx].image;
- VulkanTexture *texture = SDL_calloc(1, sizeof(VulkanTexture));
- texture->swizzle = SwizzleForSDLFormat(format);
- texture->depth = 1;
- texture->usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
- SDL_SetAtomicInt(&texture->referenceCount, 0);
- texture->image = vkImage;
- texture->externallyManaged = true;
- texture->aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
- texture->subresourceCount = createInfo.arraySize * createInfo.mipCount;
- texture->subresources = SDL_calloc(
- texture->subresourceCount,
- sizeof(VulkanTextureSubresource));
- for (i = 0; i < createInfo.arraySize; i += 1) {
- for (j = 0; j < createInfo.mipCount; j += 1) {
- Uint32 subresourceIndex = VULKAN_INTERNAL_GetTextureSubresourceIndex(
- j,
- i,
- createInfo.mipCount);
- if (createInfo.usageFlags & XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT) {
- texture->subresources[subresourceIndex].renderTargetViews = SDL_malloc(sizeof(VkImageView));
- if (!VULKAN_INTERNAL_CreateRenderTargetView(
- renderer,
- texture,
- i,
- j,
- SDLToVK_TextureFormat[format],
- texture->swizzle,
- &texture->subresources[subresourceIndex].renderTargetViews[0])) {
- VULKAN_INTERNAL_DestroyTexture(renderer, texture);
- SDL_SetError("Failed to create render target view");
- return XR_ERROR_RUNTIME_FAILURE;
- }
- }
- texture->subresources[subresourceIndex].parent = texture;
- texture->subresources[subresourceIndex].layer = i;
- texture->subresources[subresourceIndex].level = j;
- }
- }
- // Transition to the default barrier state
- VulkanCommandBuffer *barrierCommandBuffer = (VulkanCommandBuffer *)VULKAN_AcquireCommandBuffer((SDL_GPURenderer *)renderer);
- VULKAN_INTERNAL_TextureTransitionToDefaultUsage(
- renderer,
- barrierCommandBuffer,
- VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED,
- texture);
- VULKAN_INTERNAL_TrackTexture(barrierCommandBuffer, texture);
- VULKAN_Submit((SDL_GPUCommandBuffer *)barrierCommandBuffer);
- textureContainers[idx] = SDL_malloc(sizeof(VulkanTextureContainer));
- VulkanTextureContainer *container = textureContainers[idx];
- SDL_zero(container->header.info);
- container->header.info.width = createInfo.width;
- container->header.info.height = createInfo.height;
- container->header.info.format = format;
- container->header.info.layer_count_or_depth = createInfo.arraySize;
- container->header.info.num_levels = createInfo.mipCount;
- container->header.info.sample_count = SDL_GPU_SAMPLECOUNT_1;
- container->header.info.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
- container->externallyManaged = true;
- container->canBeCycled = false;
- 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;
- }
- *textures = (SDL_GPUTexture **)textureContainers;
- SDL_free(swapchainImages);
- return XR_SUCCESS;
- #else
- SDL_SetError("SDL not built with OpenXR support");
- return XR_ERROR_FUNCTION_UNSUPPORTED;
- #endif
- }
- static XrResult VULKAN_CreateXRSession(
- SDL_GPURenderer *driverData,
- const XrSessionCreateInfo *createinfo,
- XrSession *session)
- {
- #ifdef HAVE_GPU_OPENXR
- VulkanRenderer *renderer = (VulkanRenderer *)driverData;
- // Copy out the existing next ptr so that we can append it to the end of the chain we create
- const void *XR_MAY_ALIAS currentNextPtr = createinfo->next;
- // KHR_vulkan_enable and KHR_vulkan_enable2 share this structure, so we don't need to change any logic here to handle both
- XrGraphicsBindingVulkanKHR graphicsBinding = {};
- graphicsBinding.type = XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR;
- graphicsBinding.instance = renderer->instance;
- graphicsBinding.physicalDevice = renderer->physicalDevice;
- graphicsBinding.device = renderer->logicalDevice;
- graphicsBinding.queueFamilyIndex = renderer->queueFamilyIndex;
- graphicsBinding.queueIndex = 0; // we only ever have one queue, so hardcode queue index 0
- graphicsBinding.next = currentNextPtr;
- XrSessionCreateInfo sessionCreateInfo = *createinfo;
- sessionCreateInfo.systemId = renderer->xrSystemId;
- sessionCreateInfo.next = &graphicsBinding;
- return renderer->xr->xrCreateSession(renderer->xrInstance, &sessionCreateInfo, session);
- #else
- SDL_SetError("SDL not built with OpenXR support");
- return XR_ERROR_FUNCTION_UNSUPPORTED;
- #endif
- }
- 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;
- renderer->minimumVkVersion = VK_API_VERSION_1_0;
- #ifdef HAVE_GPU_OPENXR
- bool xr = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_ENABLE_BOOLEAN, false);
- XrInstance *xrInstance = SDL_GetPointerProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_INSTANCE_POINTER, NULL);
- XrSystemId *xrSystemId = SDL_GetPointerProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_SYSTEM_ID_POINTER, NULL);
- if (xr) {
- XrExtensionProperties gpuExtension;
- if (!xrInstance) {
- SDL_SetError("You must specify an out pointer for the OpenXR instance");
- SDL_free(renderer);
- SDL_Vulkan_UnloadLibrary();
- return NULL;
- }
- if (!xrSystemId) {
- SDL_SetError("You must specify an out pointer for the OpenXR system ID");
- SDL_free(renderer);
- SDL_Vulkan_UnloadLibrary();
- return NULL;
- }
- if (!SDL_OpenXR_LoadLibrary()) {
- SDL_assert(!"This should have failed in PrepareDevice first!");
- SDL_free(renderer);
- SDL_Vulkan_UnloadLibrary();
- return NULL;
- }
- if (!VULKAN_INTERNAL_SearchForOpenXrGpuExtension(&gpuExtension)) {
- SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to find a compatible OpenXR vulkan extension");
- SDL_OpenXR_UnloadLibrary();
- SDL_free(renderer);
- SDL_Vulkan_UnloadLibrary();
- return NULL;
- }
- if (!SDL_OPENXR_INTERNAL_GPUInitOpenXR(debugMode, gpuExtension, props, xrInstance, xrSystemId, &renderer->xr)) {
- SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to init OpenXR");
- SDL_OpenXR_UnloadLibrary();
- SDL_free(renderer);
- SDL_Vulkan_UnloadLibrary();
- return NULL;
- }
- renderer->xrInstance = *xrInstance;
- renderer->xrSystemId = *xrSystemId;
- XrVersion minimumVulkanApiVersion;
- if (VULKAN_INTERNAL_GetXrMinimumVulkanApiVersion(&minimumVulkanApiVersion, *xrInstance, *xrSystemId) != XR_SUCCESS) {
- SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get OpenXR graphics requirements");
- renderer->xr->xrDestroyInstance(*xrInstance);
- SDL_OpenXR_UnloadLibrary();
- SDL_free(renderer->xr);
- SDL_free(renderer);
- SDL_Vulkan_UnloadLibrary();
- return NULL;
- }
- renderer->minimumVkVersion = VK_MAKE_VERSION(
- XR_VERSION_MAJOR(minimumVulkanApiVersion),
- XR_VERSION_MINOR(minimumVulkanApiVersion),
- XR_VERSION_PATCH(minimumVulkanApiVersion));
- }
- #endif // HAVE_GPU_OPENXR
- if (!VULKAN_INTERNAL_PrepareVulkan(renderer, &features, props)) {
- SET_STRING_ERROR("Failed to initialize Vulkan!");
- #ifdef HAVE_GPU_OPENXR
- if (xr) {
- renderer->xr->xrDestroyInstance(*xrInstance);
- SDL_OpenXR_UnloadLibrary();
- SDL_free(renderer->xr);
- }
- #endif // HAVE_GPU_OPENXR
- 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
|