runloop.c 269 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118
  1. /* RetroArch - A frontend for libretro.
  2. * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
  3. * Copyright (C) 2011-2021 - Daniel De Matteis
  4. * Copyright (C) 2012-2015 - Michael Lelli
  5. * Copyright (C) 2014-2017 - Jean-Andr� Santoni
  6. * Copyright (C) 2016-2019 - Brad Parker
  7. * Copyright (C) 2016-2019 - Andr�s Su�rez (input mapper code)
  8. * Copyright (C) 2016-2017 - Gregor Richards (network code)
  9. *
  10. * RetroArch is free software: you can redistribute it and/or modify it under the terms
  11. * of the GNU General Public License as published by the Free Software Found-
  12. * ation, either version 3 of the License, or (at your option) any later version.
  13. *
  14. * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  15. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  16. * PURPOSE. See the GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along with RetroArch.
  19. * If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #include <stdbool.h>
  22. #ifdef _WIN32
  23. #ifdef _XBOX
  24. #include <xtl.h>
  25. #else
  26. #define WIN32_LEAN_AND_MEAN
  27. #include <windows.h>
  28. #endif
  29. #if defined(DEBUG) && defined(HAVE_DRMINGW)
  30. #include "exchndl.h"
  31. #endif
  32. #endif
  33. #if defined(DINGUX)
  34. #include <sys/types.h>
  35. #include <unistd.h>
  36. #endif
  37. #if (defined(__linux__) || defined(__unix__) || defined(DINGUX)) && !defined(EMSCRIPTEN)
  38. #include <signal.h>
  39. #endif
  40. #if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
  41. #ifndef LEGACY_WIN32
  42. #define LEGACY_WIN32
  43. #endif
  44. #endif
  45. #if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
  46. #include <objbase.h>
  47. #include <process.h>
  48. #endif
  49. #include <stdio.h>
  50. #include <stdlib.h>
  51. #include <stdarg.h>
  52. #include <stdint.h>
  53. #include <string.h>
  54. #include <ctype.h>
  55. #include <math.h>
  56. #include <locale.h>
  57. #include <boolean.h>
  58. #include <clamping.h>
  59. #include <string/stdstring.h>
  60. #include <dynamic/dylib.h>
  61. #include <file/config_file.h>
  62. #include <lists/string_list.h>
  63. #include <memalign.h>
  64. #include <retro_math.h>
  65. #include <retro_timers.h>
  66. #include <encodings/utf.h>
  67. #include <libretro.h>
  68. #ifdef HAVE_VULKAN
  69. #include <libretro_vulkan.h>
  70. #endif
  71. #define VFS_FRONTEND
  72. #include <vfs/vfs_implementation.h>
  73. #include <features/features_cpu.h>
  74. #include <compat/strl.h>
  75. #include <compat/strcasestr.h>
  76. #include <compat/getopt.h>
  77. #include <compat/posix_string.h>
  78. #include <streams/file_stream.h>
  79. #include <file/file_path.h>
  80. #include <retro_miscellaneous.h>
  81. #include <queues/message_queue.h>
  82. #include <lists/dir_list.h>
  83. #ifdef EMSCRIPTEN
  84. #include <emscripten/emscripten.h>
  85. #endif
  86. #ifdef HAVE_LIBNX
  87. #include <switch.h>
  88. #endif
  89. #if defined(HAVE_LAKKA) || defined(HAVE_LIBNX)
  90. #include "switch_performance_profiles.h"
  91. #endif
  92. #if defined(ANDROID)
  93. #include "play_feature_delivery/play_feature_delivery.h"
  94. #endif
  95. #ifdef HAVE_PRESENCE
  96. #include "network/presence.h"
  97. #endif
  98. #ifdef HAVE_DISCORD
  99. #include "network/discord.h"
  100. #endif
  101. #include "config.def.h"
  102. #include "runtime_file.h"
  103. #include "runloop.h"
  104. #include "camera/camera_driver.h"
  105. #include "location_driver.h"
  106. #include "record/record_driver.h"
  107. #ifdef HAVE_CONFIG_H
  108. #include "config.h"
  109. #endif
  110. #ifdef HAVE_NETWORKING
  111. #include <net/net_compat.h>
  112. #include <net/net_socket.h>
  113. #endif
  114. #include <audio/audio_resampler.h>
  115. #include "audio/audio_driver.h"
  116. #include "gfx/gfx_animation.h"
  117. #include "gfx/gfx_display.h"
  118. #include "gfx/gfx_thumbnail.h"
  119. #include "gfx/video_filter.h"
  120. #include "input/input_osk.h"
  121. #ifdef HAVE_RUNAHEAD
  122. #include "runahead.h"
  123. #endif
  124. #ifdef HAVE_MENU
  125. #include "menu/menu_cbs.h"
  126. #include "menu/menu_driver.h"
  127. #include "menu/menu_input.h"
  128. #include "menu/menu_input_bind_dialog.h"
  129. #endif
  130. #ifdef HAVE_MENU
  131. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  132. #include "menu/menu_shader.h"
  133. #endif
  134. #endif
  135. #ifdef HAVE_GFX_WIDGETS
  136. #include "gfx/gfx_widgets.h"
  137. #endif
  138. #include "input/input_keymaps.h"
  139. #include "input/input_remapping.h"
  140. #ifdef HAVE_CHEEVOS
  141. #include "cheevos/cheevos.h"
  142. #include "cheevos/cheevos_menu.h"
  143. #endif
  144. #ifdef HAVE_NETWORKING
  145. #include "network/netplay/netplay.h"
  146. #include "network/netplay/netplay_private.h"
  147. #ifdef HAVE_WIFI
  148. #include "network/wifi_driver.h"
  149. #endif
  150. #endif
  151. #ifdef HAVE_THREADS
  152. #include <rthreads/rthreads.h>
  153. #endif
  154. #include "autosave.h"
  155. #include "command.h"
  156. #include "config.features.h"
  157. #include "cores/internal_cores.h"
  158. #include "content.h"
  159. #include "core_info.h"
  160. #include "dynamic.h"
  161. #include "defaults.h"
  162. #include "msg_hash.h"
  163. #include "paths.h"
  164. #include "file_path_special.h"
  165. #include "ui/ui_companion_driver.h"
  166. #include "verbosity.h"
  167. #include "frontend/frontend_driver.h"
  168. #ifdef HAVE_THREADS
  169. #include "gfx/video_thread_wrapper.h"
  170. #endif
  171. #include "gfx/video_display_server.h"
  172. #ifdef HAVE_CRTSWITCHRES
  173. #include "gfx/video_crt_switch.h"
  174. #endif
  175. #ifdef HAVE_BLUETOOTH
  176. #include "bluetooth/bluetooth_driver.h"
  177. #endif
  178. #include "misc/cpufreq/cpufreq.h"
  179. #include "led/led_driver.h"
  180. #include "midi_driver.h"
  181. #include "location_driver.h"
  182. #include "core.h"
  183. #include "configuration.h"
  184. #include "list_special.h"
  185. #include "core_option_manager.h"
  186. #ifdef HAVE_CHEATS
  187. #include "cheat_manager.h"
  188. #endif
  189. #ifdef HAVE_REWIND
  190. #include "state_manager.h"
  191. #endif
  192. #include "tasks/task_content.h"
  193. #include "tasks/task_file_transfer.h"
  194. #include "tasks/task_powerstate.h"
  195. #include "tasks/tasks_internal.h"
  196. #include "performance_counters.h"
  197. #include "version.h"
  198. #include "version_git.h"
  199. #include "retroarch.h"
  200. #include "accessibility.h"
  201. #if defined(HAVE_SDL) || defined(HAVE_SDL2) || defined(HAVE_SDL_DINGUX)
  202. #include "SDL.h"
  203. #endif
  204. #ifdef HAVE_LAKKA
  205. #include "lakka.h"
  206. #endif
  207. #if defined(HAVE_COCOATOUCH) && TARGET_OS_IOS
  208. #include "JITSupport.h"
  209. #endif
  210. #define SHADER_FILE_WATCH_DELAY_MSEC 500
  211. #define QUIT_DELAY_USEC 3 * 1000000 /* 3 seconds */
  212. #define DEFAULT_NETWORK_GAMEPAD_PORT 55400
  213. #define UDP_FRAME_PACKETS 16
  214. #ifdef HAVE_ZLIB
  215. #define DEFAULT_EXT "zip"
  216. #else
  217. #define DEFAULT_EXT ""
  218. #endif
  219. #ifdef HAVE_DYNAMIC
  220. #define SYMBOL(x) do { \
  221. function_t func = dylib_proc(lib_handle_local, #x); \
  222. memcpy(&current_core->x, &func, sizeof(func)); \
  223. if (!current_core->x) { RARCH_ERR("Failed to load symbol: \"%s\"\n", #x); retroarch_fail(1, "runloop_init_libretro_symbols()"); } \
  224. } while (0)
  225. #else
  226. #define SYMBOL(x) current_core->x = x
  227. #endif
  228. #define SYMBOL_DUMMY(x) current_core->x = libretro_dummy_##x
  229. #ifdef HAVE_FFMPEG
  230. #define SYMBOL_FFMPEG(x) current_core->x = libretro_ffmpeg_##x
  231. #endif
  232. #ifdef HAVE_MPV
  233. #define SYMBOL_MPV(x) current_core->x = libretro_mpv_##x
  234. #endif
  235. #ifdef HAVE_IMAGEVIEWER
  236. #define SYMBOL_IMAGEVIEWER(x) current_core->x = libretro_imageviewer_##x
  237. #endif
  238. #if defined(HAVE_NETWORKING) && defined(HAVE_NETWORKGAMEPAD)
  239. #define SYMBOL_NETRETROPAD(x) current_core->x = libretro_netretropad_##x
  240. #endif
  241. #if defined(HAVE_VIDEOPROCESSOR)
  242. #define SYMBOL_VIDEOPROCESSOR(x) current_core->x = libretro_videoprocessor_##x
  243. #endif
  244. #define CORE_SYMBOLS(x) \
  245. x(retro_init); \
  246. x(retro_deinit); \
  247. x(retro_api_version); \
  248. x(retro_get_system_info); \
  249. x(retro_get_system_av_info); \
  250. x(retro_set_environment); \
  251. x(retro_set_video_refresh); \
  252. x(retro_set_audio_sample); \
  253. x(retro_set_audio_sample_batch); \
  254. x(retro_set_input_poll); \
  255. x(retro_set_input_state); \
  256. x(retro_set_controller_port_device); \
  257. x(retro_reset); \
  258. x(retro_run); \
  259. x(retro_serialize_size); \
  260. x(retro_serialize); \
  261. x(retro_unserialize); \
  262. x(retro_cheat_reset); \
  263. x(retro_cheat_set); \
  264. x(retro_load_game); \
  265. x(retro_load_game_special); \
  266. x(retro_unload_game); \
  267. x(retro_get_region); \
  268. x(retro_get_memory_data); \
  269. x(retro_get_memory_size);
  270. #ifdef _WIN32
  271. #define PERF_LOG_FMT "[PERF]: Avg (%s): %I64u ticks, %I64u runs.\n"
  272. #else
  273. #define PERF_LOG_FMT "[PERF]: Avg (%s): %llu ticks, %llu runs.\n"
  274. #endif
  275. static runloop_state_t runloop_state = {};
  276. /* GLOBAL POINTER GETTERS */
  277. runloop_state_t *runloop_state_get_ptr(void)
  278. {
  279. return &runloop_state;
  280. }
  281. #ifdef HAVE_REWIND
  282. bool state_manager_frame_is_reversed(void)
  283. {
  284. return (runloop_state.rewind_st.flags & STATE_MGR_REWIND_ST_FLAG_FRAME_IS_REVERSED) > 0;
  285. }
  286. #endif
  287. content_state_t *content_state_get_ptr(void)
  288. {
  289. return &runloop_state.content_st;
  290. }
  291. /* Get the current subsystem rom id */
  292. unsigned content_get_subsystem_rom_id(void)
  293. {
  294. return runloop_state.content_st.pending_subsystem_rom_id;
  295. }
  296. /* Get the current subsystem */
  297. int content_get_subsystem(void)
  298. {
  299. return runloop_state.content_st.pending_subsystem_id;
  300. }
  301. struct retro_perf_counter **retro_get_perf_counter_libretro(void)
  302. {
  303. return runloop_state.perf_counters_libretro;
  304. }
  305. unsigned retro_get_perf_count_libretro(void)
  306. {
  307. return runloop_state.perf_ptr_libretro;
  308. }
  309. void runloop_performance_counter_register(struct retro_perf_counter *perf)
  310. {
  311. if ( perf->registered
  312. || runloop_state.perf_ptr_libretro >= MAX_COUNTERS)
  313. return;
  314. runloop_state.perf_counters_libretro[runloop_state.perf_ptr_libretro++] = perf;
  315. perf->registered = true;
  316. }
  317. void runloop_log_counters(
  318. struct retro_perf_counter **counters, unsigned num)
  319. {
  320. int i;
  321. for (i = 0; i < (int)num; i++)
  322. {
  323. if (counters[i]->call_cnt)
  324. {
  325. RARCH_LOG(PERF_LOG_FMT,
  326. counters[i]->ident,
  327. (uint64_t)counters[i]->total /
  328. (uint64_t)counters[i]->call_cnt,
  329. (uint64_t)counters[i]->call_cnt);
  330. }
  331. }
  332. }
  333. static void runloop_perf_log(void)
  334. {
  335. RARCH_LOG("[PERF]: Performance counters (libretro):\n");
  336. runloop_log_counters(runloop_state.perf_counters_libretro,
  337. runloop_state.perf_ptr_libretro);
  338. }
  339. static bool runloop_environ_cb_get_system_info(unsigned cmd, void *data)
  340. {
  341. runloop_state_t *runloop_st = &runloop_state;
  342. rarch_system_info_t *system = &runloop_st->system;
  343. switch (cmd)
  344. {
  345. case RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME:
  346. *runloop_st->load_no_content_hook = *(const bool*)data;
  347. break;
  348. case RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO:
  349. {
  350. size_t i, j, size;
  351. const struct retro_subsystem_info *info =
  352. (const struct retro_subsystem_info*)data;
  353. settings_t *settings = config_get_ptr();
  354. unsigned log_level = settings->uints.libretro_log_level;
  355. runloop_st->subsystem_current_count = 0;
  356. RARCH_LOG("[Environ]: SET_SUBSYSTEM_INFO.\n");
  357. for (i = 0; info[i].ident; i++)
  358. {
  359. if (log_level != RETRO_LOG_DEBUG)
  360. continue;
  361. RARCH_DBG("Subsystem ID: %d\nSpecial game type: %s\n Ident: %s\n ID: %u\n Content:\n",
  362. i,
  363. info[i].desc,
  364. info[i].ident,
  365. info[i].id
  366. );
  367. for (j = 0; j < info[i].num_roms; j++)
  368. {
  369. RARCH_DBG(" %s (%s)\n",
  370. info[i].roms[j].desc, info[i].roms[j].required ?
  371. "required" : "optional");
  372. }
  373. }
  374. size = i;
  375. if (log_level == RETRO_LOG_DEBUG)
  376. {
  377. RARCH_DBG("Subsystems: %d\n", i);
  378. if (size > SUBSYSTEM_MAX_SUBSYSTEMS)
  379. RARCH_WARN("Subsystems exceed subsystem max, clamping to %d\n", SUBSYSTEM_MAX_SUBSYSTEMS);
  380. }
  381. if (system)
  382. {
  383. for (i = 0; i < size && i < SUBSYSTEM_MAX_SUBSYSTEMS; i++)
  384. {
  385. struct retro_subsystem_info *subsys_info = &runloop_st->subsystem_data[i];
  386. struct retro_subsystem_rom_info *subsys_rom_info = runloop_st->subsystem_data_roms[i];
  387. /* Nasty, but have to do it like this since
  388. * the pointers are const char *
  389. * (if we don't free them, we get a memory leak) */
  390. if (!string_is_empty(subsys_info->desc))
  391. free((char *)subsys_info->desc);
  392. if (!string_is_empty(subsys_info->ident))
  393. free((char *)subsys_info->ident);
  394. subsys_info->desc = strdup(info[i].desc);
  395. subsys_info->ident = strdup(info[i].ident);
  396. subsys_info->id = info[i].id;
  397. subsys_info->num_roms = info[i].num_roms;
  398. if (log_level == RETRO_LOG_DEBUG)
  399. if (subsys_info->num_roms > SUBSYSTEM_MAX_SUBSYSTEM_ROMS)
  400. RARCH_WARN("Subsystems exceed subsystem max roms, clamping to %d\n", SUBSYSTEM_MAX_SUBSYSTEM_ROMS);
  401. for (j = 0; j < subsys_info->num_roms && j < SUBSYSTEM_MAX_SUBSYSTEM_ROMS; j++)
  402. {
  403. /* Nasty, but have to do it like this since
  404. * the pointers are const char *
  405. * (if we don't free them, we get a memory leak) */
  406. if (!string_is_empty(subsys_rom_info[j].desc))
  407. free((char *)
  408. subsys_rom_info[j].desc);
  409. if (!string_is_empty(
  410. subsys_rom_info[j].valid_extensions))
  411. free((char *)
  412. subsys_rom_info[j].valid_extensions);
  413. subsys_rom_info[j].desc =
  414. strdup(info[i].roms[j].desc);
  415. subsys_rom_info[j].valid_extensions =
  416. strdup(info[i].roms[j].valid_extensions);
  417. subsys_rom_info[j].required =
  418. info[i].roms[j].required;
  419. subsys_rom_info[j].block_extract =
  420. info[i].roms[j].block_extract;
  421. subsys_rom_info[j].need_fullpath =
  422. info[i].roms[j].need_fullpath;
  423. }
  424. subsys_info->roms = subsys_rom_info;
  425. }
  426. runloop_st->subsystem_current_count =
  427. size <= SUBSYSTEM_MAX_SUBSYSTEMS
  428. ? (unsigned)size
  429. : SUBSYSTEM_MAX_SUBSYSTEMS;
  430. }
  431. break;
  432. }
  433. default:
  434. return false;
  435. }
  436. return true;
  437. }
  438. #ifdef HAVE_DYNAMIC
  439. /**
  440. * libretro_get_environment_info:
  441. * @func : Function pointer for get_environment_info.
  442. * @load_no_content : If true, core should be able to auto-start
  443. * without any content loaded.
  444. *
  445. * Sets environment callback in order to get statically known
  446. * information from it.
  447. *
  448. * Fetched via environment callbacks instead of
  449. * retro_get_system_info(), as this info is part of extensions.
  450. *
  451. * Should only be called once right after core load to
  452. * avoid overwriting the "real" environ callback.
  453. *
  454. * For statically linked cores, pass retro_set_environment as argument.
  455. */
  456. void libretro_get_environment_info(
  457. void (*func)(retro_environment_t),
  458. bool *load_no_content)
  459. {
  460. runloop_state_t *runloop_st = &runloop_state;
  461. runloop_st->load_no_content_hook = load_no_content;
  462. /* load_no_content gets set in this callback. */
  463. func(runloop_environ_cb_get_system_info);
  464. /* It's possible that we just set get_system_info callback
  465. * to the currently running core.
  466. *
  467. * Make sure we reset it to the actual environment callback.
  468. * Ignore any environment callbacks here in case we're running
  469. * on the non-current core. */
  470. runloop_st->flags |= RUNLOOP_FLAG_IGNORE_ENVIRONMENT_CB;
  471. func(runloop_environment_cb);
  472. runloop_st->flags &= ~RUNLOOP_FLAG_IGNORE_ENVIRONMENT_CB;
  473. }
  474. static dylib_t load_dynamic_core(const char *path, char *buf,
  475. size_t size)
  476. {
  477. #if defined(ANDROID)
  478. /* Can't resolve symlinks when dealing with cores
  479. * installed via play feature delivery, because the
  480. * source files have non-standard file names (which
  481. * will not be recognised by regular core handling
  482. * routines) */
  483. bool resolve_symlinks = !play_feature_delivery_enabled();
  484. #else
  485. bool resolve_symlinks = true;
  486. #endif
  487. /* Can't lookup symbols in itself on UWP */
  488. #if !(defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
  489. if (dylib_proc(NULL, "retro_init"))
  490. {
  491. /* Try to verify that -lretro was not linked in from other modules
  492. * since loading it dynamically and with -l will fail hard. */
  493. RARCH_ERR("Serious problem. RetroArch wants to load libretro cores"
  494. " dynamically, but it is already linked.\n");
  495. RARCH_ERR("This could happen if other modules RetroArch depends on "
  496. "link against libretro directly.\n");
  497. RARCH_ERR("Proceeding could cause a crash. Aborting ...\n");
  498. retroarch_fail(1, "load_dynamic_core()");
  499. }
  500. #endif
  501. /* Need to use absolute path for this setting. It can be
  502. * saved to content history, and a relative path would
  503. * break in that scenario. */
  504. path_resolve_realpath(buf, size, resolve_symlinks);
  505. return dylib_load(path);
  506. }
  507. static dylib_t libretro_get_system_info_lib(const char *path,
  508. struct retro_system_info *info, bool *load_no_content)
  509. {
  510. dylib_t lib = dylib_load(path);
  511. void (*proc)(struct retro_system_info*);
  512. if (!lib)
  513. return NULL;
  514. proc = (void (*)(struct retro_system_info*))
  515. dylib_proc(lib, "retro_get_system_info");
  516. if (!proc)
  517. {
  518. dylib_close(lib);
  519. return NULL;
  520. }
  521. proc(info);
  522. if (load_no_content)
  523. {
  524. void (*set_environ)(retro_environment_t);
  525. *load_no_content = false;
  526. set_environ = (void (*)(retro_environment_t))
  527. dylib_proc(lib, "retro_set_environment");
  528. if (set_environ)
  529. libretro_get_environment_info(set_environ, load_no_content);
  530. }
  531. return lib;
  532. }
  533. #endif
  534. static void runloop_update_runtime_log(
  535. runloop_state_t *runloop_st,
  536. const char *dir_runtime_log,
  537. const char *dir_playlist,
  538. bool log_per_core)
  539. {
  540. /* Initialise runtime log file */
  541. runtime_log_t *runtime_log = runtime_log_init(
  542. runloop_st->runtime_content_path,
  543. runloop_st->runtime_core_path,
  544. dir_runtime_log,
  545. dir_playlist,
  546. log_per_core);
  547. if (!runtime_log)
  548. return;
  549. /* Add additional runtime */
  550. runtime_log_add_runtime_usec(runtime_log,
  551. runloop_st->core_runtime_usec);
  552. /* Update 'last played' entry */
  553. runtime_log_set_last_played_now(runtime_log);
  554. /* Save runtime log file */
  555. runtime_log_save(runtime_log);
  556. /* Clean up */
  557. free(runtime_log);
  558. }
  559. void runloop_runtime_log_deinit(
  560. runloop_state_t *runloop_st,
  561. bool content_runtime_log,
  562. bool content_runtime_log_aggregate,
  563. const char *dir_runtime_log,
  564. const char *dir_playlist)
  565. {
  566. if (verbosity_is_enabled())
  567. {
  568. char log[PATH_MAX_LENGTH] = {0};
  569. unsigned hours = 0;
  570. unsigned minutes = 0;
  571. unsigned seconds = 0;
  572. runtime_log_convert_usec2hms(
  573. runloop_st->core_runtime_usec,
  574. &hours, &minutes, &seconds);
  575. /* TODO/FIXME - localize */
  576. snprintf(log, sizeof(log),
  577. "[Core]: Content ran for a total of:"
  578. " %02u hours, %02u minutes, %02u seconds.",
  579. hours, minutes, seconds);
  580. RARCH_LOG("%s\n", log);
  581. }
  582. /* Only write to file if content has run for a non-zero length of time */
  583. if (runloop_st->core_runtime_usec > 0)
  584. {
  585. /* Per core logging */
  586. if (content_runtime_log)
  587. runloop_update_runtime_log(runloop_st, dir_runtime_log, dir_playlist, true);
  588. /* Aggregate logging */
  589. if (content_runtime_log_aggregate)
  590. runloop_update_runtime_log(runloop_st, dir_runtime_log, dir_playlist, false);
  591. }
  592. /* Reset runtime + content/core paths, to prevent any
  593. * possibility of duplicate logging */
  594. runloop_st->core_runtime_usec = 0;
  595. memset(runloop_st->runtime_content_path, 0,
  596. sizeof(runloop_st->runtime_content_path));
  597. memset(runloop_st->runtime_core_path, 0,
  598. sizeof(runloop_st->runtime_core_path));
  599. }
  600. static bool runloop_clear_all_thread_waits(
  601. unsigned clear_threads, void *data)
  602. {
  603. if (clear_threads > 0)
  604. audio_driver_start(false);
  605. else
  606. audio_driver_stop();
  607. return true;
  608. }
  609. static bool dynamic_verify_hw_context(
  610. const char *video_ident,
  611. bool driver_switch_enable,
  612. enum retro_hw_context_type type,
  613. unsigned minor, unsigned major)
  614. {
  615. if (!driver_switch_enable)
  616. {
  617. switch (type)
  618. {
  619. case RETRO_HW_CONTEXT_VULKAN:
  620. if (!string_is_equal(video_ident, "vulkan"))
  621. return false;
  622. break;
  623. #if defined(HAVE_OPENGL_CORE)
  624. case RETRO_HW_CONTEXT_OPENGL_CORE:
  625. if (!string_is_equal(video_ident, "glcore"))
  626. return false;
  627. break;
  628. #else
  629. case RETRO_HW_CONTEXT_OPENGL_CORE:
  630. #endif
  631. case RETRO_HW_CONTEXT_OPENGLES2:
  632. case RETRO_HW_CONTEXT_OPENGLES3:
  633. case RETRO_HW_CONTEXT_OPENGLES_VERSION:
  634. case RETRO_HW_CONTEXT_OPENGL:
  635. if (!string_is_equal(video_ident, "gl") &&
  636. !string_is_equal(video_ident, "glcore"))
  637. return false;
  638. break;
  639. case RETRO_HW_CONTEXT_D3D10:
  640. if (!string_is_equal(video_ident, "d3d10"))
  641. return false;
  642. break;
  643. case RETRO_HW_CONTEXT_D3D11:
  644. if (!string_is_equal(video_ident, "d3d11"))
  645. return false;
  646. break;
  647. case RETRO_HW_CONTEXT_D3D12:
  648. if (!string_is_equal(video_ident, "d3d12"))
  649. return false;
  650. break;
  651. default:
  652. break;
  653. }
  654. }
  655. return true;
  656. }
  657. static bool dynamic_request_hw_context(enum retro_hw_context_type type,
  658. unsigned minor, unsigned major)
  659. {
  660. switch (type)
  661. {
  662. case RETRO_HW_CONTEXT_NONE:
  663. RARCH_LOG("Requesting no HW context.\n");
  664. break;
  665. case RETRO_HW_CONTEXT_VULKAN:
  666. #ifdef HAVE_VULKAN
  667. RARCH_LOG("Requesting Vulkan context.\n");
  668. break;
  669. #else
  670. RARCH_ERR("Requesting Vulkan context, but RetroArch is not compiled against Vulkan. Cannot use HW context.\n");
  671. return false;
  672. #endif
  673. #if defined(HAVE_OPENGLES)
  674. #if (defined(HAVE_OPENGLES2) || defined(HAVE_OPENGLES3))
  675. case RETRO_HW_CONTEXT_OPENGLES2:
  676. case RETRO_HW_CONTEXT_OPENGLES3:
  677. RARCH_LOG("Requesting OpenGLES%u context.\n",
  678. type == RETRO_HW_CONTEXT_OPENGLES2 ? 2 : 3);
  679. break;
  680. #if defined(HAVE_OPENGLES3)
  681. case RETRO_HW_CONTEXT_OPENGLES_VERSION:
  682. #ifndef HAVE_OPENGLES3_2
  683. if (major == 3 && minor == 2)
  684. {
  685. RARCH_ERR("Requesting OpenGLES%u.%u context, but RetroArch is compiled against a lesser version. Cannot use HW context.\n",
  686. major, minor);
  687. return false;
  688. }
  689. #endif
  690. #if !defined(HAVE_OPENGLES3_2) && !defined(HAVE_OPENGLES3_1)
  691. if (major == 3 && minor == 1)
  692. {
  693. RARCH_ERR("Requesting OpenGLES%u.%u context, but RetroArch is compiled against a lesser version. Cannot use HW context.\n",
  694. major, minor);
  695. return false;
  696. }
  697. #endif
  698. RARCH_LOG("Requesting OpenGLES%u.%u context.\n",
  699. major, minor);
  700. break;
  701. #endif
  702. #endif
  703. case RETRO_HW_CONTEXT_OPENGL:
  704. case RETRO_HW_CONTEXT_OPENGL_CORE:
  705. RARCH_ERR("Requesting OpenGL context, but RetroArch "
  706. "is compiled against OpenGLES. Cannot use HW context.\n");
  707. return false;
  708. #elif defined(HAVE_OPENGL) || defined(HAVE_OPENGL_CORE)
  709. case RETRO_HW_CONTEXT_OPENGLES2:
  710. case RETRO_HW_CONTEXT_OPENGLES3:
  711. RARCH_ERR("Requesting OpenGLES%u context, but RetroArch "
  712. "is compiled against OpenGL. Cannot use HW context.\n",
  713. type == RETRO_HW_CONTEXT_OPENGLES2 ? 2 : 3);
  714. return false;
  715. case RETRO_HW_CONTEXT_OPENGLES_VERSION:
  716. RARCH_ERR("Requesting OpenGLES%u.%u context, but RetroArch "
  717. "is compiled against OpenGL. Cannot use HW context.\n",
  718. major, minor);
  719. return false;
  720. case RETRO_HW_CONTEXT_OPENGL:
  721. RARCH_LOG("Requesting OpenGL context.\n");
  722. break;
  723. case RETRO_HW_CONTEXT_OPENGL_CORE:
  724. /* TODO/FIXME - we should do a check here to see if
  725. * the requested core GL version is supported */
  726. RARCH_LOG("Requesting core OpenGL context (%u.%u).\n",
  727. major, minor);
  728. break;
  729. #endif
  730. #if defined(HAVE_D3D11)
  731. case RETRO_HW_CONTEXT_D3D11:
  732. RARCH_LOG("Requesting D3D11 context.\n");
  733. break;
  734. #endif
  735. #ifdef HAVE_D3D10
  736. case RETRO_HW_CONTEXT_D3D10:
  737. RARCH_LOG("Requesting D3D10 context.\n");
  738. break;
  739. #endif
  740. #ifdef HAVE_D3D12
  741. case RETRO_HW_CONTEXT_D3D12:
  742. RARCH_LOG("Requesting D3D12 context.\n");
  743. break;
  744. #endif
  745. #if defined(HAVE_D3D9)
  746. case RETRO_HW_CONTEXT_D3D9:
  747. RARCH_LOG("Requesting D3D9 context.\n");
  748. break;
  749. #endif
  750. default:
  751. RARCH_LOG("Requesting unknown context.\n");
  752. return false;
  753. }
  754. return true;
  755. }
  756. static void libretro_log_cb(
  757. enum retro_log_level level,
  758. const char *fmt, ...)
  759. {
  760. va_list vp;
  761. settings_t *settings = config_get_ptr();
  762. unsigned libretro_log_level = settings->uints.libretro_log_level;
  763. if ((unsigned)level < libretro_log_level)
  764. return;
  765. if (!verbosity_is_enabled())
  766. return;
  767. va_start(vp, fmt);
  768. switch (level)
  769. {
  770. case RETRO_LOG_DEBUG:
  771. RARCH_LOG_V("[libretro DEBUG]", fmt, vp);
  772. break;
  773. case RETRO_LOG_INFO:
  774. RARCH_LOG_OUTPUT_V("[libretro INFO]", fmt, vp);
  775. break;
  776. case RETRO_LOG_WARN:
  777. RARCH_WARN_V("[libretro WARN]", fmt, vp);
  778. break;
  779. case RETRO_LOG_ERROR:
  780. RARCH_ERR_V("[libretro ERROR]", fmt, vp);
  781. break;
  782. default:
  783. break;
  784. }
  785. va_end(vp);
  786. }
  787. static size_t mmap_add_bits_down(size_t n)
  788. {
  789. n |= n >> 1;
  790. n |= n >> 2;
  791. n |= n >> 4;
  792. n |= n >> 8;
  793. n |= n >> 16;
  794. /* double shift to avoid warnings on 32bit (it's dead code,
  795. * but compilers suck) */
  796. if (sizeof(size_t) > 4)
  797. n |= n >> 16 >> 16;
  798. return n;
  799. }
  800. static size_t mmap_inflate(size_t addr, size_t mask)
  801. {
  802. while (mask)
  803. {
  804. size_t tmp = (mask - 1) & ~mask;
  805. /* to put in an 1 bit instead, OR in tmp+1 */
  806. addr = ((addr & ~tmp) << 1) | (addr & tmp);
  807. mask = mask & (mask - 1);
  808. }
  809. return addr;
  810. }
  811. static size_t mmap_reduce(size_t addr, size_t mask)
  812. {
  813. while (mask)
  814. {
  815. size_t tmp = (mask - 1) & ~mask;
  816. addr = (addr & tmp) | ((addr >> 1) & ~tmp);
  817. mask = (mask & (mask - 1)) >> 1;
  818. }
  819. return addr;
  820. }
  821. static size_t mmap_highest_bit(size_t n)
  822. {
  823. n = mmap_add_bits_down(n);
  824. return n ^ (n >> 1);
  825. }
  826. static bool mmap_preprocess_descriptors(
  827. rarch_memory_descriptor_t *first, unsigned count)
  828. {
  829. size_t top_addr = 1;
  830. rarch_memory_descriptor_t *desc = NULL;
  831. const rarch_memory_descriptor_t *end = first + count;
  832. size_t highest_reachable = 0;
  833. for (desc = first; desc < end; desc++)
  834. {
  835. if (desc->core.select != 0)
  836. top_addr |= desc->core.select;
  837. else
  838. top_addr |= desc->core.start + desc->core.len - 1;
  839. }
  840. top_addr = mmap_add_bits_down(top_addr);
  841. for (desc = first; desc < end; desc++)
  842. {
  843. if (desc->core.select == 0)
  844. {
  845. if (desc->core.len == 0)
  846. return false;
  847. if ((desc->core.len & (desc->core.len - 1)) != 0)
  848. return false;
  849. desc->core.select = top_addr
  850. & ~mmap_inflate(mmap_add_bits_down(desc->core.len - 1),
  851. desc->core.disconnect);
  852. }
  853. if (desc->core.len == 0)
  854. desc->core.len = mmap_add_bits_down(
  855. mmap_reduce(top_addr & ~desc->core.select,
  856. desc->core.disconnect)) + 1;
  857. if (desc->core.start & ~desc->core.select)
  858. return false;
  859. highest_reachable = mmap_inflate(desc->core.len - 1,
  860. desc->core.disconnect);
  861. /* Disconnect unselected bits that are too high to ever
  862. * index into the core's buffer. Higher addresses will
  863. * repeat / mirror the buffer as long as they match select */
  864. while (mmap_highest_bit(top_addr
  865. & ~desc->core.select
  866. & ~desc->core.disconnect) >
  867. mmap_highest_bit(highest_reachable))
  868. desc->core.disconnect |= mmap_highest_bit(top_addr
  869. & ~desc->core.select
  870. & ~desc->core.disconnect);
  871. }
  872. return true;
  873. }
  874. static void runloop_deinit_core_options(
  875. bool game_options_active,
  876. const char *path_core_options,
  877. core_option_manager_t *core_options)
  878. {
  879. /* Check whether game-specific options file is being used */
  880. if (!string_is_empty(path_core_options))
  881. {
  882. config_file_t *conf_tmp = NULL;
  883. /* We only need to save configuration settings for
  884. * the current core
  885. * > If game-specific options file exists, have
  886. * to read it (to ensure file only gets written
  887. * if config values change)
  888. * > Otherwise, create a new, empty config_file_t
  889. * object */
  890. if (path_is_valid(path_core_options))
  891. conf_tmp = config_file_new_from_path_to_string(path_core_options);
  892. if (!conf_tmp)
  893. conf_tmp = config_file_new_alloc();
  894. if (conf_tmp)
  895. {
  896. core_option_manager_flush(
  897. core_options,
  898. conf_tmp);
  899. RARCH_LOG("[Core]: Saved %s-specific core options to \"%s\".\n",
  900. game_options_active ? "game" : "folder", path_core_options);
  901. config_file_write(conf_tmp, path_core_options, true);
  902. config_file_free(conf_tmp);
  903. conf_tmp = NULL;
  904. }
  905. path_clear(RARCH_PATH_CORE_OPTIONS);
  906. }
  907. else
  908. {
  909. const char *path = core_options->conf_path;
  910. core_option_manager_flush(
  911. core_options,
  912. core_options->conf);
  913. RARCH_LOG("[Core]: Saved core options file to \"%s\".\n", path);
  914. config_file_write(core_options->conf, path, true);
  915. }
  916. if (core_options)
  917. core_option_manager_free(core_options);
  918. }
  919. static bool validate_per_core_options(char *s,
  920. size_t len, bool mkdir,
  921. const char *core_name, const char *game_name)
  922. {
  923. char config_directory[PATH_MAX_LENGTH];
  924. config_directory[0] = '\0';
  925. if ( (!s)
  926. || (len < 1)
  927. || string_is_empty(core_name)
  928. || string_is_empty(game_name))
  929. return false;
  930. fill_pathname_application_special(config_directory,
  931. sizeof(config_directory), APPLICATION_SPECIAL_DIRECTORY_CONFIG);
  932. fill_pathname_join_special_ext(s,
  933. config_directory, core_name, game_name,
  934. ".opt", len);
  935. /* No need to make a directory if file already exists... */
  936. if (mkdir && !path_is_valid(s))
  937. {
  938. char new_path[PATH_MAX_LENGTH];
  939. fill_pathname_join_special(new_path,
  940. config_directory, core_name, sizeof(new_path));
  941. if (!path_is_directory(new_path))
  942. path_mkdir(new_path);
  943. }
  944. return true;
  945. }
  946. static bool validate_game_options(
  947. const char *core_name,
  948. char *s, size_t len, bool mkdir)
  949. {
  950. const char *game_name = path_basename_nocompression(path_get(RARCH_PATH_BASENAME));
  951. return validate_per_core_options(s, len, mkdir,
  952. core_name, game_name);
  953. }
  954. /**
  955. * game_specific_options:
  956. *
  957. * @return true if a game specific core
  958. * options path has been found, otherwise false.
  959. **/
  960. static bool validate_game_specific_options(char **output)
  961. {
  962. char game_options_path[PATH_MAX_LENGTH];
  963. runloop_state_t *runloop_st = &runloop_state;
  964. game_options_path[0] = '\0';
  965. if (!validate_game_options(
  966. runloop_st->system.info.library_name,
  967. game_options_path,
  968. sizeof(game_options_path), false) ||
  969. !path_is_valid(game_options_path))
  970. return false;
  971. RARCH_LOG("[Core]: %s \"%s\".\n",
  972. msg_hash_to_str(MSG_GAME_SPECIFIC_CORE_OPTIONS_FOUND_AT),
  973. game_options_path);
  974. *output = strdup(game_options_path);
  975. return true;
  976. }
  977. static bool validate_folder_options(
  978. char *s, size_t len, bool mkdir)
  979. {
  980. char folder_name[PATH_MAX_LENGTH];
  981. runloop_state_t *runloop_st = &runloop_state;
  982. const char *core_name = runloop_st->system.info.library_name;
  983. const char *game_path = path_get(RARCH_PATH_BASENAME);
  984. folder_name[0] = '\0';
  985. if (string_is_empty(game_path))
  986. return false;
  987. fill_pathname_parent_dir_name(folder_name,
  988. game_path, sizeof(folder_name));
  989. return validate_per_core_options(s, len, mkdir,
  990. core_name, folder_name);
  991. }
  992. /**
  993. * validate_folder_specific_options:
  994. *
  995. * @return true if a folder specific core
  996. * options path has been found, otherwise false.
  997. **/
  998. static bool validate_folder_specific_options(
  999. char **output)
  1000. {
  1001. char folder_options_path[PATH_MAX_LENGTH];
  1002. folder_options_path[0] ='\0';
  1003. if (!validate_folder_options(
  1004. folder_options_path,
  1005. sizeof(folder_options_path), false) ||
  1006. !path_is_valid(folder_options_path))
  1007. return false;
  1008. RARCH_LOG("[Core]: %s \"%s\".\n",
  1009. msg_hash_to_str(MSG_FOLDER_SPECIFIC_CORE_OPTIONS_FOUND_AT),
  1010. folder_options_path);
  1011. *output = strdup(folder_options_path);
  1012. return true;
  1013. }
  1014. /**
  1015. * runloop_init_core_options_path:
  1016. *
  1017. * Fetches core options path for current core/content
  1018. * - path: path from which options should be read
  1019. * from/saved to
  1020. * - src_path: in the event that 'path' file does not
  1021. * yet exist, provides source path from which initial
  1022. * options should be extracted
  1023. *
  1024. * NOTE: caller must ensure
  1025. * path and src_path are NULL-terminated
  1026. *
  1027. **/
  1028. static void runloop_init_core_options_path(
  1029. settings_t *settings,
  1030. char *path, size_t len,
  1031. char *src_path, size_t src_len)
  1032. {
  1033. char *game_options_path = NULL;
  1034. char *folder_options_path = NULL;
  1035. runloop_state_t *runloop_st = &runloop_state;
  1036. bool game_specific_options = settings->bools.game_specific_options;
  1037. /* Check whether game-specific options exist */
  1038. if (game_specific_options &&
  1039. validate_game_specific_options(&game_options_path))
  1040. {
  1041. /* Notify system that we have a valid core options
  1042. * override */
  1043. path_set(RARCH_PATH_CORE_OPTIONS, game_options_path);
  1044. runloop_st->flags &= ~RUNLOOP_FLAG_FOLDER_OPTIONS_ACTIVE;
  1045. runloop_st->flags |= RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE;
  1046. /* Copy options path */
  1047. strlcpy(path, game_options_path, len);
  1048. free(game_options_path);
  1049. }
  1050. /* Check whether folder-specific options exist */
  1051. else if (game_specific_options &&
  1052. validate_folder_specific_options(
  1053. &folder_options_path))
  1054. {
  1055. /* Notify system that we have a valid core options
  1056. * override */
  1057. path_set(RARCH_PATH_CORE_OPTIONS, folder_options_path);
  1058. runloop_st->flags &= ~RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE;
  1059. runloop_st->flags |= RUNLOOP_FLAG_FOLDER_OPTIONS_ACTIVE;
  1060. /* Copy options path */
  1061. strlcpy(path, folder_options_path, len);
  1062. free(folder_options_path);
  1063. }
  1064. else
  1065. {
  1066. char global_options_path[PATH_MAX_LENGTH];
  1067. char per_core_options_path[PATH_MAX_LENGTH];
  1068. bool per_core_options_exist = false;
  1069. bool per_core_options = !settings->bools.global_core_options;
  1070. const char *path_core_options = settings->paths.path_core_options;
  1071. per_core_options_path[0] = '\0';
  1072. if (per_core_options)
  1073. {
  1074. const char *core_name = runloop_st->system.info.library_name;
  1075. /* Get core-specific options path
  1076. * > if validate_per_core_options() returns
  1077. * false, then per-core options are disabled (due to
  1078. * unknown system errors...) */
  1079. per_core_options = validate_per_core_options(
  1080. per_core_options_path, sizeof(per_core_options_path), true,
  1081. core_name, core_name);
  1082. /* If we can use per-core options, check whether an options
  1083. * file already exists */
  1084. if (per_core_options)
  1085. per_core_options_exist = path_is_valid(per_core_options_path);
  1086. }
  1087. /* If not using per-core options, or if a per-core options
  1088. * file does not yet exist, must fetch 'global' options path */
  1089. if (!per_core_options || !per_core_options_exist)
  1090. {
  1091. const char *options_path = path_core_options;
  1092. if (!string_is_empty(options_path))
  1093. strlcpy(global_options_path,
  1094. options_path, sizeof(global_options_path));
  1095. else if (!path_is_empty(RARCH_PATH_CONFIG))
  1096. fill_pathname_resolve_relative(
  1097. global_options_path, path_get(RARCH_PATH_CONFIG),
  1098. FILE_PATH_CORE_OPTIONS_CONFIG, sizeof(global_options_path));
  1099. }
  1100. /* Allocate correct path/src_path strings */
  1101. if (per_core_options)
  1102. {
  1103. strlcpy(path, per_core_options_path, len);
  1104. if (!per_core_options_exist)
  1105. strlcpy(src_path, global_options_path, src_len);
  1106. }
  1107. else
  1108. strlcpy(path, global_options_path, len);
  1109. /* Notify system that we *do not* have a valid core options
  1110. * options override */
  1111. runloop_st->flags &= ~(RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE
  1112. | RUNLOOP_FLAG_FOLDER_OPTIONS_ACTIVE);
  1113. }
  1114. }
  1115. static core_option_manager_t *runloop_init_core_options(
  1116. settings_t *settings,
  1117. const struct retro_core_options_v2 *options_v2)
  1118. {
  1119. bool categories_enabled = settings->bools.core_option_category_enable;
  1120. char options_path[PATH_MAX_LENGTH];
  1121. char src_options_path[PATH_MAX_LENGTH];
  1122. /* Ensure these are NULL-terminated */
  1123. options_path[0] = '\0';
  1124. src_options_path[0] = '\0';
  1125. /* Get core options file path */
  1126. runloop_init_core_options_path(settings,
  1127. options_path, sizeof(options_path),
  1128. src_options_path, sizeof(src_options_path));
  1129. if (!string_is_empty(options_path))
  1130. return core_option_manager_new(options_path,
  1131. src_options_path, options_v2,
  1132. categories_enabled);
  1133. return NULL;
  1134. }
  1135. static core_option_manager_t *runloop_init_core_variables(
  1136. settings_t *settings, const struct retro_variable *vars)
  1137. {
  1138. char options_path[PATH_MAX_LENGTH];
  1139. char src_options_path[PATH_MAX_LENGTH];
  1140. /* Ensure these are NULL-terminated */
  1141. options_path[0] = '\0';
  1142. src_options_path[0] = '\0';
  1143. /* Get core options file path */
  1144. runloop_init_core_options_path(
  1145. settings,
  1146. options_path, sizeof(options_path),
  1147. src_options_path, sizeof(src_options_path));
  1148. if (!string_is_empty(options_path))
  1149. return core_option_manager_new_vars(options_path, src_options_path, vars);
  1150. return NULL;
  1151. }
  1152. static void runloop_core_msg_queue_push(
  1153. struct retro_system_av_info *av_info,
  1154. const struct retro_message_ext *msg)
  1155. {
  1156. double fps;
  1157. unsigned duration_frames;
  1158. enum message_queue_category category;
  1159. /* Assign category */
  1160. switch (msg->level)
  1161. {
  1162. case RETRO_LOG_WARN:
  1163. category = MESSAGE_QUEUE_CATEGORY_WARNING;
  1164. break;
  1165. case RETRO_LOG_ERROR:
  1166. category = MESSAGE_QUEUE_CATEGORY_ERROR;
  1167. break;
  1168. case RETRO_LOG_INFO:
  1169. case RETRO_LOG_DEBUG:
  1170. default:
  1171. category = MESSAGE_QUEUE_CATEGORY_INFO;
  1172. break;
  1173. }
  1174. /* Get duration in frames */
  1175. fps = (av_info && (av_info->timing.fps > 0)) ? av_info->timing.fps : 60.0;
  1176. duration_frames = (unsigned)((fps * (float)msg->duration / 1000.0f) + 0.5f);
  1177. /* Note: Do not flush the message queue here - a core
  1178. * may need to send multiple notifications simultaneously */
  1179. runloop_msg_queue_push(msg->msg,
  1180. msg->priority, duration_frames,
  1181. false, NULL, MESSAGE_QUEUE_ICON_DEFAULT,
  1182. category);
  1183. }
  1184. static void core_performance_counter_start(
  1185. struct retro_perf_counter *perf)
  1186. {
  1187. runloop_state_t *runloop_st = &runloop_state;
  1188. bool runloop_perfcnt_enable = runloop_st->perfcnt_enable;
  1189. if (runloop_perfcnt_enable)
  1190. {
  1191. perf->call_cnt++;
  1192. perf->start = cpu_features_get_perf_counter();
  1193. }
  1194. }
  1195. static void core_performance_counter_stop(struct retro_perf_counter *perf)
  1196. {
  1197. runloop_state_t *runloop_st = &runloop_state;
  1198. bool runloop_perfcnt_enable = runloop_st->perfcnt_enable;
  1199. if (runloop_perfcnt_enable)
  1200. perf->total += cpu_features_get_perf_counter() - perf->start;
  1201. }
  1202. bool runloop_environment_cb(unsigned cmd, void *data)
  1203. {
  1204. unsigned p;
  1205. runloop_state_t *runloop_st = &runloop_state;
  1206. recording_state_t *recording_st = recording_state_get_ptr();
  1207. settings_t *settings = config_get_ptr();
  1208. rarch_system_info_t *system = &runloop_st->system;
  1209. bool ignore_environment_cb = runloop_st->flags &
  1210. RUNLOOP_FLAG_IGNORE_ENVIRONMENT_CB;
  1211. if (ignore_environment_cb)
  1212. return false;
  1213. /* RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE gets called
  1214. * by every core on every frame. Handle it first,
  1215. * to avoid the overhead of traversing the subsequent
  1216. * (enormous) case statement */
  1217. if (cmd == RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE)
  1218. {
  1219. if (runloop_st->core_options)
  1220. *(bool*)data = runloop_st->core_options->updated;
  1221. else
  1222. *(bool*)data = false;
  1223. return true;
  1224. }
  1225. switch (cmd)
  1226. {
  1227. case RETRO_ENVIRONMENT_GET_OVERSCAN:
  1228. {
  1229. bool video_crop_overscan = settings->bools.video_crop_overscan;
  1230. *(bool*)data = !video_crop_overscan;
  1231. RARCH_LOG("[Environ]: GET_OVERSCAN: %u\n",
  1232. (unsigned)!video_crop_overscan);
  1233. }
  1234. break;
  1235. case RETRO_ENVIRONMENT_GET_CAN_DUPE:
  1236. *(bool*)data = true;
  1237. RARCH_LOG("[Environ]: GET_CAN_DUPE: true\n");
  1238. break;
  1239. case RETRO_ENVIRONMENT_GET_VARIABLE:
  1240. {
  1241. struct retro_variable *var = (struct retro_variable*)data;
  1242. size_t opt_idx;
  1243. if (!var)
  1244. return true;
  1245. var->value = NULL;
  1246. if (!runloop_st->core_options)
  1247. {
  1248. RARCH_ERR("[Environ]: GET_VARIABLE: %s - %s.\n",
  1249. var->key, "Not implemented");
  1250. return true;
  1251. }
  1252. #ifdef HAVE_RUNAHEAD
  1253. if (runloop_st->core_options->updated)
  1254. runloop_st->flags |= RUNLOOP_FLAG_HAS_VARIABLE_UPDATE;
  1255. #endif
  1256. runloop_st->core_options->updated = false;
  1257. if (core_option_manager_get_idx(runloop_st->core_options,
  1258. var->key, &opt_idx))
  1259. var->value = core_option_manager_get_val(
  1260. runloop_st->core_options, opt_idx);
  1261. if (!var->value)
  1262. {
  1263. RARCH_ERR("[Environ]: GET_VARIABLE: %s - %s.\n",
  1264. var->key, "Invalid value");
  1265. return true;
  1266. }
  1267. RARCH_DBG("[Environ]: GET_VARIABLE: %s = \"%s\"\n",
  1268. var->key, var->value);
  1269. }
  1270. break;
  1271. case RETRO_ENVIRONMENT_SET_VARIABLE:
  1272. {
  1273. const struct retro_variable *var = (const struct retro_variable*)data;
  1274. size_t opt_idx;
  1275. size_t val_idx;
  1276. /* If core passes NULL to the callback, return
  1277. * value indicates whether callback is supported */
  1278. if (!var)
  1279. return true;
  1280. if ( string_is_empty(var->key)
  1281. || string_is_empty(var->value))
  1282. return false;
  1283. if (!runloop_st->core_options)
  1284. {
  1285. RARCH_ERR("[Environ]: SET_VARIABLE: %s - %s.\n",
  1286. var->key, "Not implemented");
  1287. return false;
  1288. }
  1289. /* Check whether key is valid */
  1290. if (!core_option_manager_get_idx(runloop_st->core_options,
  1291. var->key, &opt_idx))
  1292. {
  1293. RARCH_ERR("[Environ]: SET_VARIABLE: %s - %s.\n",
  1294. var->key, "Invalid key");
  1295. return false;
  1296. }
  1297. /* Check whether value is valid */
  1298. if (!core_option_manager_get_val_idx(runloop_st->core_options,
  1299. opt_idx, var->value, &val_idx))
  1300. {
  1301. RARCH_ERR("[Environ]: SET_VARIABLE: %s - %s: %s\n",
  1302. var->key, "Invalid value", var->value);
  1303. return false;
  1304. }
  1305. /* Update option value if core-requested value
  1306. * is not currently set */
  1307. if (val_idx != runloop_st->core_options->opts[opt_idx].index)
  1308. core_option_manager_set_val(runloop_st->core_options,
  1309. opt_idx, val_idx, true);
  1310. RARCH_DBG("[Environ]: SET_VARIABLE: %s = \"%s\"\n",
  1311. var->key, var->value);
  1312. }
  1313. break;
  1314. /* SET_VARIABLES: Legacy path */
  1315. case RETRO_ENVIRONMENT_SET_VARIABLES:
  1316. RARCH_LOG("[Environ]: SET_VARIABLES.\n");
  1317. {
  1318. core_option_manager_t *new_vars = NULL;
  1319. if (runloop_st->core_options)
  1320. {
  1321. runloop_deinit_core_options(
  1322. runloop_st->flags & RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE,
  1323. path_get(RARCH_PATH_CORE_OPTIONS),
  1324. runloop_st->core_options);
  1325. runloop_st->flags &=
  1326. ~(RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE
  1327. | RUNLOOP_FLAG_FOLDER_OPTIONS_ACTIVE);
  1328. runloop_st->core_options = NULL;
  1329. }
  1330. if ((new_vars = runloop_init_core_variables(
  1331. settings,
  1332. (const struct retro_variable *)data)))
  1333. runloop_st->core_options = new_vars;
  1334. }
  1335. break;
  1336. case RETRO_ENVIRONMENT_SET_CORE_OPTIONS:
  1337. RARCH_LOG("[Environ]: SET_CORE_OPTIONS.\n");
  1338. {
  1339. /* Parse core_option_definition array to
  1340. * create retro_core_options_v2 struct */
  1341. struct retro_core_options_v2 *options_v2 =
  1342. core_option_manager_convert_v1(
  1343. (const struct retro_core_option_definition*)data);
  1344. if (runloop_st->core_options)
  1345. {
  1346. runloop_deinit_core_options(
  1347. runloop_st->flags & RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE,
  1348. path_get(RARCH_PATH_CORE_OPTIONS),
  1349. runloop_st->core_options);
  1350. runloop_st->flags &=
  1351. ~(RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE
  1352. | RUNLOOP_FLAG_FOLDER_OPTIONS_ACTIVE);
  1353. runloop_st->core_options = NULL;
  1354. }
  1355. if (options_v2)
  1356. {
  1357. /* Initialise core options */
  1358. core_option_manager_t *new_vars = runloop_init_core_options(settings, options_v2);
  1359. if (new_vars)
  1360. runloop_st->core_options = new_vars;
  1361. /* Clean up */
  1362. core_option_manager_free_converted(options_v2);
  1363. }
  1364. }
  1365. break;
  1366. case RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL:
  1367. RARCH_LOG("[Environ]: RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL.\n");
  1368. {
  1369. /* Parse core_options_intl to create
  1370. * retro_core_options_v2 struct */
  1371. struct retro_core_options_v2 *options_v2 =
  1372. core_option_manager_convert_v1_intl(
  1373. (const struct retro_core_options_intl*)data);
  1374. if (runloop_st->core_options)
  1375. {
  1376. runloop_deinit_core_options(
  1377. runloop_st->flags & RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE,
  1378. path_get(RARCH_PATH_CORE_OPTIONS),
  1379. runloop_st->core_options);
  1380. runloop_st->flags &=
  1381. ~(RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE
  1382. | RUNLOOP_FLAG_FOLDER_OPTIONS_ACTIVE);
  1383. runloop_st->core_options = NULL;
  1384. }
  1385. if (options_v2)
  1386. {
  1387. /* Initialise core options */
  1388. core_option_manager_t *new_vars = runloop_init_core_options(settings, options_v2);
  1389. if (new_vars)
  1390. runloop_st->core_options = new_vars;
  1391. /* Clean up */
  1392. core_option_manager_free_converted(options_v2);
  1393. }
  1394. }
  1395. break;
  1396. case RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2:
  1397. RARCH_LOG("[Environ]: RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2.\n");
  1398. {
  1399. core_option_manager_t *new_vars = NULL;
  1400. const struct retro_core_options_v2 *options_v2 =
  1401. (const struct retro_core_options_v2 *)data;
  1402. bool categories_enabled =
  1403. settings->bools.core_option_category_enable;
  1404. if (runloop_st->core_options)
  1405. {
  1406. runloop_deinit_core_options(
  1407. runloop_st->flags & RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE,
  1408. path_get(RARCH_PATH_CORE_OPTIONS),
  1409. runloop_st->core_options);
  1410. runloop_st->flags &=
  1411. ~(RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE
  1412. | RUNLOOP_FLAG_FOLDER_OPTIONS_ACTIVE);
  1413. runloop_st->core_options = NULL;
  1414. }
  1415. if (options_v2)
  1416. {
  1417. new_vars = runloop_init_core_options(settings, options_v2);
  1418. if (new_vars)
  1419. runloop_st->core_options = new_vars;
  1420. }
  1421. /* Return value does not indicate success.
  1422. * Callback returns 'true' if core option
  1423. * categories are supported/enabled,
  1424. * otherwise 'false'. */
  1425. return categories_enabled;
  1426. }
  1427. break;
  1428. case RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL:
  1429. RARCH_LOG("[Environ]: RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL.\n");
  1430. {
  1431. /* Parse retro_core_options_v2_intl to create
  1432. * retro_core_options_v2 struct */
  1433. core_option_manager_t *new_vars = NULL;
  1434. struct retro_core_options_v2 *options_v2 =
  1435. core_option_manager_convert_v2_intl(
  1436. (const struct retro_core_options_v2_intl*)data);
  1437. bool categories_enabled =
  1438. settings->bools.core_option_category_enable;
  1439. if (runloop_st->core_options)
  1440. {
  1441. runloop_deinit_core_options(
  1442. runloop_st->flags & RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE,
  1443. path_get(RARCH_PATH_CORE_OPTIONS),
  1444. runloop_st->core_options);
  1445. runloop_st->flags &=
  1446. ~(RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE
  1447. | RUNLOOP_FLAG_FOLDER_OPTIONS_ACTIVE);
  1448. runloop_st->core_options = NULL;
  1449. }
  1450. if (options_v2)
  1451. {
  1452. /* Initialise core options */
  1453. new_vars = runloop_init_core_options(settings, options_v2);
  1454. if (new_vars)
  1455. runloop_st->core_options = new_vars;
  1456. /* Clean up */
  1457. core_option_manager_free_converted(options_v2);
  1458. }
  1459. /* Return value does not indicate success.
  1460. * Callback returns 'true' if core option
  1461. * categories are supported/enabled,
  1462. * otherwise 'false'. */
  1463. return categories_enabled;
  1464. }
  1465. break;
  1466. case RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY:
  1467. RARCH_DBG("[Environ]: RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY.\n");
  1468. {
  1469. const struct retro_core_option_display *core_options_display =
  1470. (const struct retro_core_option_display *)data;
  1471. if (runloop_st->core_options && core_options_display)
  1472. core_option_manager_set_visible(
  1473. runloop_st->core_options,
  1474. core_options_display->key,
  1475. core_options_display->visible);
  1476. }
  1477. break;
  1478. case RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK:
  1479. RARCH_DBG("[Environ]: RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK.\n");
  1480. {
  1481. const struct retro_core_options_update_display_callback
  1482. *update_display_callback =
  1483. (const struct retro_core_options_update_display_callback*)data;
  1484. if (update_display_callback &&
  1485. update_display_callback->callback)
  1486. runloop_st->core_options_callback.update_display =
  1487. update_display_callback->callback;
  1488. else
  1489. runloop_st->core_options_callback.update_display = NULL;
  1490. }
  1491. break;
  1492. case RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION:
  1493. RARCH_LOG("[Environ]: GET_MESSAGE_INTERFACE_VERSION.\n");
  1494. /* Current API version is 1 */
  1495. *(unsigned *)data = 1;
  1496. break;
  1497. case RETRO_ENVIRONMENT_SET_MESSAGE:
  1498. {
  1499. const struct retro_message *msg = (const struct retro_message*)data;
  1500. #if defined(HAVE_GFX_WIDGETS)
  1501. dispgfx_widget_t *p_dispwidget = dispwidget_get_ptr();
  1502. if (p_dispwidget->active)
  1503. gfx_widget_set_libretro_message(
  1504. msg->msg,
  1505. roundf((float)msg->frames / 60.0f * 1000.0f));
  1506. else
  1507. #endif
  1508. runloop_msg_queue_push(msg->msg, 3, msg->frames,
  1509. true, NULL, MESSAGE_QUEUE_ICON_DEFAULT,
  1510. MESSAGE_QUEUE_CATEGORY_INFO);
  1511. RARCH_LOG("[Environ]: SET_MESSAGE: %s\n", msg->msg);
  1512. break;
  1513. }
  1514. case RETRO_ENVIRONMENT_SET_MESSAGE_EXT:
  1515. {
  1516. const struct retro_message_ext *msg =
  1517. (const struct retro_message_ext*)data;
  1518. /* Log message, if required */
  1519. if (msg->target != RETRO_MESSAGE_TARGET_OSD)
  1520. {
  1521. switch (msg->level)
  1522. {
  1523. case RETRO_LOG_DEBUG:
  1524. RARCH_DBG("[Environ]: SET_MESSAGE_EXT: %s\n", msg->msg);
  1525. break;
  1526. case RETRO_LOG_WARN:
  1527. RARCH_WARN("[Environ]: SET_MESSAGE_EXT: %s\n", msg->msg);
  1528. break;
  1529. case RETRO_LOG_ERROR:
  1530. RARCH_ERR("[Environ]: SET_MESSAGE_EXT: %s\n", msg->msg);
  1531. break;
  1532. case RETRO_LOG_INFO:
  1533. default:
  1534. RARCH_LOG("[Environ]: SET_MESSAGE_EXT: %s\n", msg->msg);
  1535. break;
  1536. }
  1537. }
  1538. /* Display message via OSD, if required */
  1539. if (msg->target != RETRO_MESSAGE_TARGET_LOG)
  1540. {
  1541. switch (msg->type)
  1542. {
  1543. /* Handle 'status' messages */
  1544. case RETRO_MESSAGE_TYPE_STATUS:
  1545. /* Note: We need to lock a mutex here. Strictly
  1546. * speaking, 'core_status_msg' is not part
  1547. * of the message queue, but:
  1548. * - It may be implemented as a queue in the future
  1549. * - It seems unnecessary to create a new slock_t
  1550. * object for this type of message when
  1551. * _runloop_msg_queue_lock is already available
  1552. * We therefore just call runloop_msg_queue_lock()/
  1553. * runloop_msg_queue_unlock() in this case */
  1554. RUNLOOP_MSG_QUEUE_LOCK(runloop_st);
  1555. /* If a message is already set, only overwrite
  1556. * it if the new message has the same or higher
  1557. * priority */
  1558. if (!runloop_st->core_status_msg.set ||
  1559. (runloop_st->core_status_msg.priority <= msg->priority))
  1560. {
  1561. if (!string_is_empty(msg->msg))
  1562. {
  1563. strlcpy(runloop_st->core_status_msg.str, msg->msg,
  1564. sizeof(runloop_st->core_status_msg.str));
  1565. runloop_st->core_status_msg.duration = (float)msg->duration;
  1566. runloop_st->core_status_msg.set = true;
  1567. }
  1568. else
  1569. {
  1570. /* Ensure sane behaviour if core sends an
  1571. * empty message */
  1572. runloop_st->core_status_msg.str[0] = '\0';
  1573. runloop_st->core_status_msg.priority = 0;
  1574. runloop_st->core_status_msg.duration = 0.0f;
  1575. runloop_st->core_status_msg.set = false;
  1576. }
  1577. }
  1578. RUNLOOP_MSG_QUEUE_UNLOCK(runloop_st);
  1579. break;
  1580. #if defined(HAVE_GFX_WIDGETS)
  1581. /* Handle 'alternate' non-queued notifications */
  1582. case RETRO_MESSAGE_TYPE_NOTIFICATION_ALT:
  1583. {
  1584. video_driver_state_t *video_st =
  1585. video_state_get_ptr();
  1586. dispgfx_widget_t *p_dispwidget = dispwidget_get_ptr();
  1587. if (p_dispwidget->active)
  1588. gfx_widget_set_libretro_message(
  1589. msg->msg, msg->duration);
  1590. else
  1591. runloop_core_msg_queue_push(
  1592. &video_st->av_info, msg);
  1593. }
  1594. break;
  1595. /* Handle 'progress' messages */
  1596. case RETRO_MESSAGE_TYPE_PROGRESS:
  1597. {
  1598. video_driver_state_t *video_st =
  1599. video_state_get_ptr();
  1600. dispgfx_widget_t *p_dispwidget = dispwidget_get_ptr();
  1601. if (p_dispwidget->active)
  1602. gfx_widget_set_progress_message(
  1603. msg->msg, msg->duration,
  1604. msg->priority, msg->progress);
  1605. else
  1606. runloop_core_msg_queue_push(
  1607. &video_st->av_info, msg);
  1608. }
  1609. break;
  1610. #endif
  1611. /* Handle standard (queued) notifications */
  1612. case RETRO_MESSAGE_TYPE_NOTIFICATION:
  1613. default:
  1614. {
  1615. video_driver_state_t *video_st =
  1616. video_state_get_ptr();
  1617. runloop_core_msg_queue_push(
  1618. &video_st->av_info, msg);
  1619. }
  1620. break;
  1621. }
  1622. }
  1623. break;
  1624. }
  1625. case RETRO_ENVIRONMENT_SET_ROTATION:
  1626. {
  1627. unsigned rotation = *(const unsigned*)data;
  1628. bool video_allow_rotate = settings->bools.video_allow_rotate;
  1629. RARCH_LOG("[Environ]: SET_ROTATION: %u\n", rotation);
  1630. if (system)
  1631. system->core_requested_rotation = rotation;
  1632. if (!video_allow_rotate)
  1633. return false;
  1634. if (system)
  1635. system->rotation = rotation;
  1636. if (!video_driver_set_rotation(rotation))
  1637. return false;
  1638. break;
  1639. }
  1640. case RETRO_ENVIRONMENT_SHUTDOWN:
  1641. {
  1642. #ifdef HAVE_MENU
  1643. struct menu_state *menu_st = menu_state_get_ptr();
  1644. #endif
  1645. /* This case occurs when a core (internally)
  1646. * requests a shutdown event */
  1647. RARCH_LOG("[Environ]: SHUTDOWN.\n");
  1648. runloop_st->flags |= RUNLOOP_FLAG_CORE_SHUTDOWN_INITIATED
  1649. | RUNLOOP_FLAG_SHUTDOWN_INITIATED;
  1650. #ifdef HAVE_MENU
  1651. /* Ensure that menu stack is flushed appropriately
  1652. * after the core has stopped running */
  1653. if (menu_st)
  1654. {
  1655. const char *content_path = path_get(RARCH_PATH_CONTENT);
  1656. menu_st->flags |= MENU_ST_FLAG_PENDING_ENV_SHUTDOWN_FLUSH;
  1657. if (!string_is_empty(content_path))
  1658. strlcpy(menu_st->pending_env_shutdown_content_path,
  1659. content_path,
  1660. sizeof(menu_st->pending_env_shutdown_content_path));
  1661. else
  1662. menu_st->pending_env_shutdown_content_path[0] = '\0';
  1663. }
  1664. #endif
  1665. break;
  1666. }
  1667. case RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL:
  1668. if (system)
  1669. {
  1670. system->performance_level = *(const unsigned*)data;
  1671. RARCH_LOG("[Environ]: PERFORMANCE_LEVEL: %u.\n",
  1672. system->performance_level);
  1673. }
  1674. break;
  1675. case RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY:
  1676. {
  1677. const char *dir_system = settings->paths.directory_system;
  1678. bool systemfiles_in_content_dir = settings->bools.systemfiles_in_content_dir;
  1679. if (string_is_empty(dir_system) || systemfiles_in_content_dir)
  1680. {
  1681. const char *fullpath = path_get(RARCH_PATH_CONTENT);
  1682. if (!string_is_empty(fullpath))
  1683. {
  1684. char tmp_path[PATH_MAX_LENGTH];
  1685. if (string_is_empty(dir_system))
  1686. RARCH_WARN("[Environ]: SYSTEM DIR is empty, assume CONTENT DIR %s\n",
  1687. fullpath);
  1688. strlcpy(tmp_path, fullpath, sizeof(tmp_path));
  1689. path_basedir(tmp_path);
  1690. dir_set(RARCH_DIR_SYSTEM, tmp_path);
  1691. }
  1692. *(const char**)data = dir_get_ptr(RARCH_DIR_SYSTEM);
  1693. RARCH_LOG("[Environ]: SYSTEM_DIRECTORY: \"%s\".\n",
  1694. dir_system);
  1695. }
  1696. else
  1697. {
  1698. *(const char**)data = dir_system;
  1699. RARCH_LOG("[Environ]: SYSTEM_DIRECTORY: \"%s\".\n",
  1700. dir_system);
  1701. }
  1702. }
  1703. break;
  1704. case RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY:
  1705. RARCH_LOG("[Environ]: GET_SAVE_DIRECTORY.\n");
  1706. *(const char**)data = runloop_st->savefile_dir;
  1707. break;
  1708. case RETRO_ENVIRONMENT_GET_USERNAME:
  1709. *(const char**)data = *settings->paths.username ?
  1710. settings->paths.username : NULL;
  1711. RARCH_LOG("[Environ]: GET_USERNAME: \"%s\".\n",
  1712. settings->paths.username);
  1713. break;
  1714. case RETRO_ENVIRONMENT_GET_LANGUAGE:
  1715. #ifdef HAVE_LANGEXTRA
  1716. {
  1717. unsigned user_lang = *msg_hash_get_uint(MSG_HASH_USER_LANGUAGE);
  1718. *(unsigned *)data = user_lang;
  1719. RARCH_LOG("[Environ]: GET_LANGUAGE: \"%u\".\n", user_lang);
  1720. }
  1721. #endif
  1722. break;
  1723. case RETRO_ENVIRONMENT_SET_PIXEL_FORMAT:
  1724. {
  1725. video_driver_state_t *video_st =
  1726. video_state_get_ptr();
  1727. enum retro_pixel_format pix_fmt =
  1728. *(const enum retro_pixel_format*)data;
  1729. switch (pix_fmt)
  1730. {
  1731. case RETRO_PIXEL_FORMAT_0RGB1555:
  1732. RARCH_LOG("[Environ]: SET_PIXEL_FORMAT: 0RGB1555.\n");
  1733. break;
  1734. case RETRO_PIXEL_FORMAT_RGB565:
  1735. RARCH_LOG("[Environ]: SET_PIXEL_FORMAT: RGB565.\n");
  1736. break;
  1737. case RETRO_PIXEL_FORMAT_XRGB8888:
  1738. RARCH_LOG("[Environ]: SET_PIXEL_FORMAT: XRGB8888.\n");
  1739. break;
  1740. default:
  1741. return false;
  1742. }
  1743. video_st->pix_fmt = pix_fmt;
  1744. break;
  1745. }
  1746. case RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS:
  1747. {
  1748. static const char *libretro_btn_desc[] = {
  1749. "B (bottom)", "Y (left)", "Select", "Start",
  1750. "D-Pad Up", "D-Pad Down", "D-Pad Left", "D-Pad Right",
  1751. "A (right)", "X (up)",
  1752. "L", "R", "L2", "R2", "L3", "R3",
  1753. };
  1754. android_environment_cb_native(cmd, data);
  1755. if (system)
  1756. {
  1757. unsigned retro_id;
  1758. const struct retro_input_descriptor *desc = NULL;
  1759. memset((void*)&system->input_desc_btn, 0,
  1760. sizeof(system->input_desc_btn));
  1761. desc = (const struct retro_input_descriptor*)data;
  1762. for (; desc->description; desc++)
  1763. {
  1764. unsigned retro_port = desc->port;
  1765. retro_id = desc->id;
  1766. if (desc->port >= MAX_USERS)
  1767. continue;
  1768. if (desc->id >= RARCH_FIRST_CUSTOM_BIND)
  1769. continue;
  1770. switch (desc->device)
  1771. {
  1772. case RETRO_DEVICE_JOYPAD:
  1773. system->input_desc_btn[retro_port]
  1774. [retro_id] = desc->description;
  1775. break;
  1776. case RETRO_DEVICE_ANALOG:
  1777. switch (retro_id)
  1778. {
  1779. case RETRO_DEVICE_ID_ANALOG_X:
  1780. switch (desc->index)
  1781. {
  1782. case RETRO_DEVICE_INDEX_ANALOG_LEFT:
  1783. system->input_desc_btn[retro_port]
  1784. [RARCH_ANALOG_LEFT_X_PLUS] = desc->description;
  1785. system->input_desc_btn[retro_port]
  1786. [RARCH_ANALOG_LEFT_X_MINUS] = desc->description;
  1787. break;
  1788. case RETRO_DEVICE_INDEX_ANALOG_RIGHT:
  1789. system->input_desc_btn[retro_port]
  1790. [RARCH_ANALOG_RIGHT_X_PLUS] = desc->description;
  1791. system->input_desc_btn[retro_port]
  1792. [RARCH_ANALOG_RIGHT_X_MINUS] = desc->description;
  1793. break;
  1794. }
  1795. break;
  1796. case RETRO_DEVICE_ID_ANALOG_Y:
  1797. switch (desc->index)
  1798. {
  1799. case RETRO_DEVICE_INDEX_ANALOG_LEFT:
  1800. system->input_desc_btn[retro_port]
  1801. [RARCH_ANALOG_LEFT_Y_PLUS] = desc->description;
  1802. system->input_desc_btn[retro_port]
  1803. [RARCH_ANALOG_LEFT_Y_MINUS] = desc->description;
  1804. break;
  1805. case RETRO_DEVICE_INDEX_ANALOG_RIGHT:
  1806. system->input_desc_btn[retro_port]
  1807. [RARCH_ANALOG_RIGHT_Y_PLUS] = desc->description;
  1808. system->input_desc_btn[retro_port]
  1809. [RARCH_ANALOG_RIGHT_Y_MINUS] = desc->description;
  1810. break;
  1811. }
  1812. break;
  1813. case RETRO_DEVICE_ID_JOYPAD_R2:
  1814. switch (desc->index)
  1815. {
  1816. case RETRO_DEVICE_INDEX_ANALOG_BUTTON:
  1817. system->input_desc_btn[retro_port]
  1818. [retro_id] = desc->description;
  1819. break;
  1820. }
  1821. break;
  1822. case RETRO_DEVICE_ID_JOYPAD_L2:
  1823. switch (desc->index)
  1824. {
  1825. case RETRO_DEVICE_INDEX_ANALOG_BUTTON:
  1826. system->input_desc_btn[retro_port]
  1827. [retro_id] = desc->description;
  1828. break;
  1829. }
  1830. break;
  1831. }
  1832. break;
  1833. }
  1834. }
  1835. RARCH_LOG("[Environ]: SET_INPUT_DESCRIPTORS:\n");
  1836. {
  1837. unsigned log_level = settings->uints.libretro_log_level;
  1838. if (log_level == RETRO_LOG_DEBUG)
  1839. {
  1840. unsigned input_driver_max_users = settings->uints.input_max_users;
  1841. for (p = 0; p < input_driver_max_users; p++)
  1842. {
  1843. unsigned mapped_port = settings->uints.input_remap_ports[p];
  1844. for (retro_id = 0; retro_id < RARCH_FIRST_CUSTOM_BIND; retro_id++)
  1845. {
  1846. const char *description = system->input_desc_btn[mapped_port][retro_id];
  1847. if (!description)
  1848. continue;
  1849. RARCH_DBG(" RetroPad, Port %u, Button \"%s\" => \"%s\"\n",
  1850. p + 1, libretro_btn_desc[retro_id], description);
  1851. }
  1852. }
  1853. }
  1854. }
  1855. runloop_st->current_core.flags |=
  1856. RETRO_CORE_FLAG_HAS_SET_INPUT_DESCRIPTORS;
  1857. }
  1858. break;
  1859. }
  1860. case RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK:
  1861. {
  1862. input_driver_state_t
  1863. *input_st = input_state_get_ptr();
  1864. const struct retro_keyboard_callback *info =
  1865. (const struct retro_keyboard_callback*)data;
  1866. retro_keyboard_event_t *frontend_key_event = &runloop_st->frontend_key_event;
  1867. retro_keyboard_event_t *key_event = &runloop_st->key_event;
  1868. RARCH_LOG("[Environ]: SET_KEYBOARD_CALLBACK.\n");
  1869. if (key_event)
  1870. *key_event = info->callback;
  1871. if (frontend_key_event && key_event)
  1872. *frontend_key_event = *key_event;
  1873. /* If a core calls RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK,
  1874. * then it is assumed that Game Focus mode is desired */
  1875. input_st->game_focus_state.core_requested = true;
  1876. break;
  1877. }
  1878. case RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION:
  1879. RARCH_LOG("[Environ]: GET_DISK_CONTROL_INTERFACE_VERSION.\n");
  1880. /* Current API version is 1 */
  1881. *(unsigned *)data = 1;
  1882. break;
  1883. case RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE:
  1884. {
  1885. const struct retro_disk_control_callback *control_cb =
  1886. (const struct retro_disk_control_callback*)data;
  1887. if (system)
  1888. {
  1889. RARCH_LOG("[Environ]: SET_DISK_CONTROL_INTERFACE.\n");
  1890. disk_control_set_callback(&system->disk_control, control_cb);
  1891. }
  1892. }
  1893. break;
  1894. case RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE:
  1895. {
  1896. const struct retro_disk_control_ext_callback *control_cb =
  1897. (const struct retro_disk_control_ext_callback*)data;
  1898. if (system)
  1899. {
  1900. RARCH_LOG("[Environ]: SET_DISK_CONTROL_EXT_INTERFACE.\n");
  1901. disk_control_set_ext_callback(&system->disk_control, control_cb);
  1902. }
  1903. }
  1904. break;
  1905. case RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER:
  1906. {
  1907. unsigned *cb = (unsigned*)data;
  1908. settings_t *settings = config_get_ptr();
  1909. const char *video_driver_name = settings->arrays.video_driver;
  1910. bool driver_switch_enable = settings->bools.driver_switch_enable;
  1911. RARCH_LOG("[Environ]: GET_PREFERRED_HW_RENDER, video driver name: %s.\n", video_driver_name);
  1912. if (string_is_equal(video_driver_name, "glcore"))
  1913. {
  1914. *cb = RETRO_HW_CONTEXT_OPENGL_CORE;
  1915. RARCH_LOG("[Environ]: GET_PREFERRED_HW_RENDER - Context callback set to RETRO_HW_CONTEXT_OPENGL_CORE.\n");
  1916. }
  1917. else if (string_is_equal(video_driver_name, "gl"))
  1918. {
  1919. *cb = RETRO_HW_CONTEXT_OPENGL;
  1920. RARCH_LOG("[Environ]: GET_PREFERRED_HW_RENDER - Context callback set to RETRO_HW_CONTEXT_OPENGL.\n");
  1921. }
  1922. else if (string_is_equal(video_driver_name, "vulkan"))
  1923. {
  1924. *cb = RETRO_HW_CONTEXT_VULKAN;
  1925. RARCH_LOG("[Environ]: GET_PREFERRED_HW_RENDER - Context callback set to RETRO_HW_CONTEXT_VULKAN.\n");
  1926. }
  1927. else if (string_is_equal(video_driver_name, "d3d11"))
  1928. {
  1929. *cb = RETRO_HW_CONTEXT_D3D11;
  1930. RARCH_LOG("[Environ]: GET_PREFERRED_HW_RENDER - Context callback set to RETRO_HW_CONTEXT_D3D11.\n");
  1931. }
  1932. else if (string_is_equal(video_driver_name, "d3d12"))
  1933. {
  1934. *cb = RETRO_HW_CONTEXT_D3D12;
  1935. RARCH_LOG("[Environ]: GET_PREFERRED_HW_RENDER - Context callback set to RETRO_HW_CONTEXT_D3D12.\n");
  1936. }
  1937. else
  1938. {
  1939. *cb = RETRO_HW_CONTEXT_NONE;
  1940. RARCH_LOG("[Environ]: GET_PREFERRED_HW_RENDER - Context callback set to RETRO_HW_CONTEXT_NONE.\n");
  1941. }
  1942. if (!driver_switch_enable)
  1943. {
  1944. RARCH_LOG("[Environ]: Driver switching disabled, GET_PREFERRED_HW_RENDER will be ignored.\n");
  1945. return false;
  1946. }
  1947. break;
  1948. }
  1949. case RETRO_ENVIRONMENT_SET_HW_RENDER:
  1950. case RETRO_ENVIRONMENT_SET_HW_RENDER | RETRO_ENVIRONMENT_EXPERIMENTAL:
  1951. {
  1952. settings_t *settings = config_get_ptr();
  1953. struct retro_hw_render_callback *cb =
  1954. (struct retro_hw_render_callback*)data;
  1955. video_driver_state_t *video_st =
  1956. video_state_get_ptr();
  1957. struct retro_hw_render_callback *hwr =
  1958. VIDEO_DRIVER_GET_HW_CONTEXT_INTERNAL(video_st);
  1959. if (!cb)
  1960. {
  1961. RARCH_ERR("[Environ]: SET_HW_RENDER - No valid callback passed, returning...\n");
  1962. return false;
  1963. }
  1964. RARCH_LOG("[Environ]: SET_HW_RENDER, context type: %s.\n", hw_render_context_name(cb->context_type, cb->version_major, cb->version_minor));
  1965. if (!dynamic_request_hw_context(
  1966. cb->context_type, cb->version_minor, cb->version_major))
  1967. {
  1968. RARCH_ERR("[Environ]: SET_HW_RENDER - Dynamic request HW context failed.\n");
  1969. return false;
  1970. }
  1971. if (!dynamic_verify_hw_context(
  1972. settings->arrays.video_driver,
  1973. settings->bools.driver_switch_enable,
  1974. cb->context_type, cb->version_minor, cb->version_major))
  1975. {
  1976. RARCH_ERR("[Environ]: SET_HW_RENDER: Dynamic verify HW context failed.\n");
  1977. return false;
  1978. }
  1979. #if defined(HAVE_OPENGL) || defined(HAVE_OPENGL_CORE)
  1980. /* TODO/FIXME - should check first if an OpenGL
  1981. * driver is running */
  1982. if (cb->context_type == RETRO_HW_CONTEXT_OPENGL_CORE)
  1983. {
  1984. /* Ensure that the rest of the frontend knows
  1985. * we have a core context */
  1986. gfx_ctx_flags_t flags;
  1987. flags.flags = 0;
  1988. BIT32_SET(flags.flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT);
  1989. video_context_driver_set_flags(&flags);
  1990. }
  1991. #endif
  1992. cb->get_current_framebuffer = video_driver_get_current_framebuffer;
  1993. cb->get_proc_address = video_driver_get_proc_address;
  1994. /* Old ABI. Don't copy garbage. */
  1995. if (cmd & RETRO_ENVIRONMENT_EXPERIMENTAL)
  1996. {
  1997. memcpy(hwr,
  1998. cb, offsetof(struct retro_hw_render_callback, stencil));
  1999. memset((uint8_t*)hwr + offsetof(struct retro_hw_render_callback, stencil),
  2000. 0, sizeof(*cb) - offsetof(struct retro_hw_render_callback, stencil));
  2001. }
  2002. else
  2003. memcpy(hwr, cb, sizeof(*cb));
  2004. RARCH_DBG("Reached end of SET_HW_RENDER.\n");
  2005. break;
  2006. }
  2007. case RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME:
  2008. {
  2009. bool state = *(const bool*)data;
  2010. RARCH_LOG("[Environ]: SET_SUPPORT_NO_GAME: %s.\n", state ? "yes" : "no");
  2011. if (state)
  2012. content_set_does_not_need_content();
  2013. else
  2014. content_unset_does_not_need_content();
  2015. break;
  2016. }
  2017. case RETRO_ENVIRONMENT_GET_LIBRETRO_PATH:
  2018. {
  2019. const char **path = (const char**)data;
  2020. RARCH_LOG("[Environ]: GET_LIBRETRO_PATH.\n");
  2021. #ifdef HAVE_DYNAMIC
  2022. *path = path_get(RARCH_PATH_CORE);
  2023. #else
  2024. *path = NULL;
  2025. #endif
  2026. break;
  2027. }
  2028. case RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK:
  2029. #ifdef HAVE_THREADS
  2030. {
  2031. recording_state_t
  2032. *recording_st = recording_state_get_ptr();
  2033. audio_driver_state_t
  2034. *audio_st = audio_state_get_ptr();
  2035. const struct
  2036. retro_audio_callback *cb = (const struct retro_audio_callback*)data;
  2037. RARCH_LOG("[Environ]: SET_AUDIO_CALLBACK.\n");
  2038. #ifdef HAVE_NETWORKING
  2039. if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
  2040. return false;
  2041. #endif
  2042. if (recording_st->data) /* A/V sync is a must. */
  2043. return false;
  2044. if (cb)
  2045. audio_st->callback = *cb;
  2046. }
  2047. break;
  2048. #else
  2049. return false;
  2050. #endif
  2051. case RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK:
  2052. {
  2053. const struct retro_frame_time_callback *info =
  2054. (const struct retro_frame_time_callback*)data;
  2055. RARCH_LOG("[Environ]: SET_FRAME_TIME_CALLBACK.\n");
  2056. #ifdef HAVE_NETWORKING
  2057. /* retro_run() will be called in very strange and
  2058. * mysterious ways, have to disable it. */
  2059. if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
  2060. return false;
  2061. #endif
  2062. runloop_st->frame_time = *info;
  2063. break;
  2064. }
  2065. case RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK:
  2066. {
  2067. const struct retro_audio_buffer_status_callback *info =
  2068. (const struct retro_audio_buffer_status_callback*)data;
  2069. RARCH_LOG("[Environ]: SET_AUDIO_BUFFER_STATUS_CALLBACK.\n");
  2070. if (info)
  2071. runloop_st->audio_buffer_status.callback = info->callback;
  2072. else
  2073. runloop_st->audio_buffer_status.callback = NULL;
  2074. break;
  2075. }
  2076. case RETRO_ENVIRONMENT_SET_MINIMUM_AUDIO_LATENCY:
  2077. {
  2078. unsigned audio_latency_default = settings->uints.audio_latency;
  2079. unsigned audio_latency_current =
  2080. (runloop_st->audio_latency > audio_latency_default) ?
  2081. runloop_st->audio_latency : audio_latency_default;
  2082. unsigned audio_latency_new;
  2083. RARCH_LOG("[Environ]: RETRO_ENVIRONMENT_SET_MINIMUM_AUDIO_LATENCY.\n");
  2084. /* Sanitise input latency value */
  2085. runloop_st->audio_latency = 0;
  2086. if (data)
  2087. runloop_st->audio_latency = *(const unsigned*)data;
  2088. if (runloop_st->audio_latency > 512)
  2089. {
  2090. RARCH_WARN("[Environ]: Requested audio latency of %u ms - limiting to maximum of 512 ms.\n",
  2091. runloop_st->audio_latency);
  2092. runloop_st->audio_latency = 512;
  2093. }
  2094. /* Determine new set-point latency value */
  2095. if (runloop_st->audio_latency >= audio_latency_default)
  2096. audio_latency_new = runloop_st->audio_latency;
  2097. else
  2098. {
  2099. if (runloop_st->audio_latency != 0)
  2100. RARCH_WARN("[Environ]: Requested audio latency of %u ms is less than frontend default of %u ms."
  2101. " Using frontend default...\n",
  2102. runloop_st->audio_latency, audio_latency_default);
  2103. audio_latency_new = audio_latency_default;
  2104. }
  2105. /* Check whether audio driver requires reinitialisation
  2106. * (Identical to RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO,
  2107. * without video driver initialisation) */
  2108. if (audio_latency_new != audio_latency_current)
  2109. {
  2110. recording_state_t
  2111. *recording_st = recording_state_get_ptr();
  2112. bool video_fullscreen = settings->bools.video_fullscreen;
  2113. int reinit_flags = DRIVERS_CMD_ALL &
  2114. ~(DRIVER_VIDEO_MASK | DRIVER_INPUT_MASK | DRIVER_MENU_MASK);
  2115. RARCH_LOG("[Environ]: Setting audio latency to %u ms.\n", audio_latency_new);
  2116. command_event(CMD_EVENT_REINIT, &reinit_flags);
  2117. video_driver_set_aspect_ratio();
  2118. /* Cannot continue recording with different
  2119. * parameters.
  2120. * Take the easiest route out and just restart
  2121. * the recording. */
  2122. if (recording_st->data)
  2123. {
  2124. runloop_msg_queue_push(
  2125. msg_hash_to_str(MSG_RESTARTING_RECORDING_DUE_TO_DRIVER_REINIT),
  2126. 2, 180, false,
  2127. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  2128. command_event(CMD_EVENT_RECORD_DEINIT, NULL);
  2129. command_event(CMD_EVENT_RECORD_INIT, NULL);
  2130. }
  2131. /* Hide mouse cursor in fullscreen mode */
  2132. if (video_fullscreen)
  2133. video_driver_hide_mouse();
  2134. }
  2135. break;
  2136. }
  2137. case RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE:
  2138. {
  2139. struct retro_rumble_interface *iface =
  2140. (struct retro_rumble_interface*)data;
  2141. RARCH_LOG("[Environ]: GET_RUMBLE_INTERFACE.\n");
  2142. iface->set_rumble_state = input_set_rumble_state;
  2143. break;
  2144. }
  2145. case RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES:
  2146. {
  2147. uint64_t *mask = (uint64_t*)data;
  2148. input_driver_state_t
  2149. *input_st = input_state_get_ptr();
  2150. RARCH_LOG("[Environ]: GET_INPUT_DEVICE_CAPABILITIES.\n");
  2151. if ( !input_st->current_driver->get_capabilities
  2152. || !input_st->current_data)
  2153. return false;
  2154. *mask = input_driver_get_capabilities();
  2155. break;
  2156. }
  2157. case RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE:
  2158. {
  2159. settings_t *settings = config_get_ptr();
  2160. bool input_sensors_enable = settings->bools.input_sensors_enable;
  2161. struct retro_sensor_interface *iface = (struct retro_sensor_interface*)data;
  2162. RARCH_LOG("[Environ]: GET_SENSOR_INTERFACE.\n");
  2163. if (!input_sensors_enable)
  2164. return false;
  2165. iface->set_sensor_state = input_set_sensor_state;
  2166. iface->get_sensor_input = input_get_sensor_state;
  2167. break;
  2168. }
  2169. case RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE:
  2170. {
  2171. struct retro_camera_callback *cb =
  2172. (struct retro_camera_callback*)data;
  2173. camera_driver_state_t *camera_st = camera_state_get_ptr();
  2174. RARCH_LOG("[Environ]: GET_CAMERA_INTERFACE.\n");
  2175. cb->start = driver_camera_start;
  2176. cb->stop = driver_camera_stop;
  2177. camera_st->cb = *cb;
  2178. camera_st->active = (cb->caps != 0);
  2179. break;
  2180. }
  2181. case RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE:
  2182. {
  2183. struct retro_location_callback *cb =
  2184. (struct retro_location_callback*)data;
  2185. location_driver_state_t
  2186. *location_st = location_state_get_ptr();
  2187. RARCH_LOG("[Environ]: GET_LOCATION_INTERFACE.\n");
  2188. cb->start = driver_location_start;
  2189. cb->stop = driver_location_stop;
  2190. cb->get_position = driver_location_get_position;
  2191. cb->set_interval = driver_location_set_interval;
  2192. if (system)
  2193. system->location_cb = *cb;
  2194. location_st->active = false;
  2195. break;
  2196. }
  2197. case RETRO_ENVIRONMENT_GET_LOG_INTERFACE:
  2198. {
  2199. struct retro_log_callback *cb = (struct retro_log_callback*)data;
  2200. RARCH_LOG("[Environ]: GET_LOG_INTERFACE.\n");
  2201. cb->log = libretro_log_cb;
  2202. break;
  2203. }
  2204. case RETRO_ENVIRONMENT_GET_PERF_INTERFACE:
  2205. {
  2206. struct retro_perf_callback *cb = (struct retro_perf_callback*)data;
  2207. RARCH_LOG("[Environ]: GET_PERF_INTERFACE.\n");
  2208. cb->get_time_usec = cpu_features_get_time_usec;
  2209. cb->get_cpu_features = cpu_features_get;
  2210. cb->get_perf_counter = cpu_features_get_perf_counter;
  2211. cb->perf_register = runloop_performance_counter_register;
  2212. cb->perf_start = core_performance_counter_start;
  2213. cb->perf_stop = core_performance_counter_stop;
  2214. cb->perf_log = runloop_perf_log;
  2215. break;
  2216. }
  2217. case RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY:
  2218. {
  2219. const char **dir = (const char**)data;
  2220. const char *dir_core_assets = settings->paths.directory_core_assets;
  2221. *dir = *dir_core_assets ? dir_core_assets : NULL;
  2222. RARCH_LOG("[Environ]: CORE_ASSETS_DIRECTORY: \"%s\".\n",
  2223. dir_core_assets);
  2224. break;
  2225. }
  2226. case RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO:
  2227. /**
  2228. * Update the system Audio/Video information.
  2229. * Will reinitialize audio/video drivers if needed.
  2230. * Used by RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO.
  2231. **/
  2232. {
  2233. const struct retro_system_av_info **info = (const struct retro_system_av_info**)&data;
  2234. video_driver_state_t *video_st = video_state_get_ptr();
  2235. struct retro_system_av_info *av_info = &video_st->av_info;
  2236. if (data)
  2237. {
  2238. int reinit_flags = DRIVERS_CMD_ALL;
  2239. settings_t *settings = config_get_ptr();
  2240. float refresh_rate = (*info)->timing.fps;
  2241. unsigned crt_switch_resolution = settings->uints.crt_switch_resolution;
  2242. bool video_fullscreen = settings->bools.video_fullscreen;
  2243. bool video_switch_refresh_rate = false;
  2244. bool no_video_reinit = true;
  2245. /* Refresh rate switch for regular displays */
  2246. if (video_display_server_has_resolution_list())
  2247. video_switch_refresh_rate_maybe(&refresh_rate, &video_switch_refresh_rate);
  2248. no_video_reinit = (
  2249. crt_switch_resolution == 0
  2250. && video_switch_refresh_rate == false
  2251. && data
  2252. && ((*info)->geometry.max_width == av_info->geometry.max_width)
  2253. && ((*info)->geometry.max_height == av_info->geometry.max_height));
  2254. /* First set new refresh rate and display rate, then after REINIT do
  2255. * another display rate change to make sure the change stays */
  2256. if (video_switch_refresh_rate && video_display_server_set_refresh_rate(refresh_rate))
  2257. video_monitor_set_refresh_rate(refresh_rate);
  2258. /* When not doing video reinit, we also must not do input and menu
  2259. * reinit, otherwise the input driver crashes and the menu gets
  2260. * corrupted. */
  2261. if (no_video_reinit)
  2262. reinit_flags =
  2263. DRIVERS_CMD_ALL &
  2264. ~(DRIVER_VIDEO_MASK | DRIVER_INPUT_MASK |
  2265. DRIVER_MENU_MASK);
  2266. RARCH_LOG("[Environ]: SET_SYSTEM_AV_INFO: %ux%u, Aspect: %.3f, FPS: %.2f, Sample rate: %.2f Hz.\n",
  2267. (*info)->geometry.base_width, (*info)->geometry.base_height,
  2268. (*info)->geometry.aspect_ratio,
  2269. (*info)->timing.fps,
  2270. (*info)->timing.sample_rate);
  2271. memcpy(av_info, *info, sizeof(*av_info));
  2272. video_st->core_frame_time = 1000000 /
  2273. ((video_st->av_info.timing.fps > 0.0) ?
  2274. video_st->av_info.timing.fps : 60.0);
  2275. command_event(CMD_EVENT_REINIT, &reinit_flags);
  2276. if (no_video_reinit)
  2277. video_driver_set_aspect_ratio();
  2278. if (video_switch_refresh_rate)
  2279. video_display_server_set_refresh_rate(refresh_rate);
  2280. /* Cannot continue recording with different parameters.
  2281. * Take the easiest route out and just restart
  2282. * the recording. */
  2283. if (recording_st->data)
  2284. {
  2285. runloop_msg_queue_push(
  2286. msg_hash_to_str(MSG_RESTARTING_RECORDING_DUE_TO_DRIVER_REINIT),
  2287. 2, 180, false,
  2288. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  2289. command_event(CMD_EVENT_RECORD_DEINIT, NULL);
  2290. command_event(CMD_EVENT_RECORD_INIT, NULL);
  2291. }
  2292. /* Hide mouse cursor in fullscreen after
  2293. * a RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO call. */
  2294. if (video_fullscreen)
  2295. video_driver_hide_mouse();
  2296. /* Recalibrate frame delay target when video reinits
  2297. * and pause frame delay when video does not reinit */
  2298. if (settings->bools.video_frame_delay_auto)
  2299. {
  2300. if (no_video_reinit)
  2301. video_st->frame_delay_pause = true;
  2302. else
  2303. video_st->frame_delay_target = 0;
  2304. }
  2305. return true;
  2306. }
  2307. return false;
  2308. }
  2309. case RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO:
  2310. {
  2311. unsigned i;
  2312. const struct retro_subsystem_info *info =
  2313. (const struct retro_subsystem_info*)data;
  2314. unsigned log_level = settings->uints.libretro_log_level;
  2315. RARCH_DBG("[Environ]: SET_SUBSYSTEM_INFO.\n");
  2316. for (i = 0; info[i].ident; i++)
  2317. {
  2318. unsigned j;
  2319. if (log_level != RETRO_LOG_DEBUG)
  2320. continue;
  2321. RARCH_DBG("Special game type: %s\n Ident: %s\n ID: %u\n Content:\n",
  2322. info[i].desc,
  2323. info[i].ident,
  2324. info[i].id
  2325. );
  2326. for (j = 0; j < info[i].num_roms; j++)
  2327. {
  2328. RARCH_DBG(" %s (%s)\n",
  2329. info[i].roms[j].desc, info[i].roms[j].required ?
  2330. "required" : "optional");
  2331. }
  2332. }
  2333. if (system)
  2334. {
  2335. struct retro_subsystem_info *info_ptr = NULL;
  2336. free(system->subsystem.data);
  2337. system->subsystem.data = NULL;
  2338. system->subsystem.size = 0;
  2339. info_ptr = (struct retro_subsystem_info*)
  2340. malloc(i * sizeof(*info_ptr));
  2341. if (!info_ptr)
  2342. return false;
  2343. system->subsystem.data = info_ptr;
  2344. memcpy(system->subsystem.data, info,
  2345. i * sizeof(*system->subsystem.data));
  2346. system->subsystem.size = i;
  2347. runloop_st->current_core.flags |=
  2348. RETRO_CORE_FLAG_HAS_SET_SUBSYSTEMS;
  2349. }
  2350. break;
  2351. }
  2352. case RETRO_ENVIRONMENT_SET_CONTROLLER_INFO:
  2353. {
  2354. unsigned i, j;
  2355. const struct retro_controller_info *info
  2356. = (const struct retro_controller_info*)data;
  2357. unsigned log_level = settings->uints.libretro_log_level;
  2358. RARCH_LOG("[Environ]: SET_CONTROLLER_INFO.\n");
  2359. for (i = 0; info[i].types; i++)
  2360. {
  2361. if (log_level != RETRO_LOG_DEBUG)
  2362. continue;
  2363. RARCH_DBG(" Controller port: %u\n", i + 1);
  2364. for (j = 0; j < info[i].num_types; j++)
  2365. RARCH_DBG(" %s (ID: %u)\n", info[i].types[j].desc,
  2366. info[i].types[j].id);
  2367. }
  2368. if (system)
  2369. {
  2370. struct retro_controller_info *info_ptr = NULL;
  2371. free(system->ports.data);
  2372. system->ports.data = NULL;
  2373. system->ports.size = 0;
  2374. info_ptr = (struct retro_controller_info*)calloc(i, sizeof(*info_ptr));
  2375. if (!info_ptr)
  2376. return false;
  2377. system->ports.data = info_ptr;
  2378. memcpy(system->ports.data, info,
  2379. i * sizeof(*system->ports.data));
  2380. system->ports.size = i;
  2381. }
  2382. break;
  2383. }
  2384. case RETRO_ENVIRONMENT_SET_MEMORY_MAPS:
  2385. {
  2386. if (system)
  2387. {
  2388. unsigned i;
  2389. const struct retro_memory_map *mmaps =
  2390. (const struct retro_memory_map*)data;
  2391. rarch_memory_descriptor_t *descriptors = NULL;
  2392. unsigned int log_level = settings->uints.libretro_log_level;
  2393. RARCH_LOG("[Environ]: SET_MEMORY_MAPS.\n");
  2394. free((void*)system->mmaps.descriptors);
  2395. system->mmaps.descriptors = 0;
  2396. system->mmaps.num_descriptors = 0;
  2397. descriptors = (rarch_memory_descriptor_t*)calloc(mmaps->num_descriptors,
  2398. sizeof(*descriptors));
  2399. if (!descriptors)
  2400. return false;
  2401. system->mmaps.descriptors = descriptors;
  2402. system->mmaps.num_descriptors = mmaps->num_descriptors;
  2403. for (i = 0; i < mmaps->num_descriptors; i++)
  2404. system->mmaps.descriptors[i].core = mmaps->descriptors[i];
  2405. mmap_preprocess_descriptors(descriptors, mmaps->num_descriptors);
  2406. if (log_level != RETRO_LOG_DEBUG)
  2407. break;
  2408. if (sizeof(void *) == 8)
  2409. RARCH_DBG(" ndx flags ptr offset start select disconn len addrspace\n");
  2410. else
  2411. RARCH_DBG(" ndx flags ptr offset start select disconn len addrspace\n");
  2412. for (i = 0; i < system->mmaps.num_descriptors; i++)
  2413. {
  2414. const rarch_memory_descriptor_t *desc =
  2415. &system->mmaps.descriptors[i];
  2416. char flags[7];
  2417. flags[0] = 'M';
  2418. if ((desc->core.flags & RETRO_MEMDESC_MINSIZE_8) == RETRO_MEMDESC_MINSIZE_8)
  2419. flags[1] = '8';
  2420. else if ((desc->core.flags & RETRO_MEMDESC_MINSIZE_4) == RETRO_MEMDESC_MINSIZE_4)
  2421. flags[1] = '4';
  2422. else if ((desc->core.flags & RETRO_MEMDESC_MINSIZE_2) == RETRO_MEMDESC_MINSIZE_2)
  2423. flags[1] = '2';
  2424. else
  2425. flags[1] = '1';
  2426. flags[2] = 'A';
  2427. if ((desc->core.flags & RETRO_MEMDESC_ALIGN_8) == RETRO_MEMDESC_ALIGN_8)
  2428. flags[3] = '8';
  2429. else if ((desc->core.flags & RETRO_MEMDESC_ALIGN_4) == RETRO_MEMDESC_ALIGN_4)
  2430. flags[3] = '4';
  2431. else if ((desc->core.flags & RETRO_MEMDESC_ALIGN_2) == RETRO_MEMDESC_ALIGN_2)
  2432. flags[3] = '2';
  2433. else
  2434. flags[3] = '1';
  2435. flags[4] = (desc->core.flags & RETRO_MEMDESC_BIGENDIAN) ? 'B' : 'b';
  2436. flags[5] = (desc->core.flags & RETRO_MEMDESC_CONST) ? 'C' : 'c';
  2437. flags[6] = 0;
  2438. RARCH_DBG(" %03u %s %p %08X %08X %08X %08X %08X %s\n",
  2439. i + 1, flags, desc->core.ptr, desc->core.offset, desc->core.start,
  2440. desc->core.select, desc->core.disconnect, desc->core.len,
  2441. desc->core.addrspace ? desc->core.addrspace : "");
  2442. }
  2443. }
  2444. else
  2445. {
  2446. RARCH_WARN("[Environ]: SET_MEMORY_MAPS, but system pointer not initialized..\n");
  2447. }
  2448. break;
  2449. }
  2450. case RETRO_ENVIRONMENT_SET_GEOMETRY:
  2451. {
  2452. video_driver_state_t *video_st = video_state_get_ptr();
  2453. struct retro_system_av_info *av_info = &video_st->av_info;
  2454. struct retro_game_geometry *geom = (struct retro_game_geometry*)&av_info->geometry;
  2455. const struct retro_game_geometry *in_geom= (const struct retro_game_geometry*)data;
  2456. if (!geom)
  2457. return false;
  2458. /* Can potentially be called every frame,
  2459. * don't do anything unless required. */
  2460. if ( (geom->base_width != in_geom->base_width) ||
  2461. (geom->base_height != in_geom->base_height) ||
  2462. (geom->aspect_ratio != in_geom->aspect_ratio))
  2463. {
  2464. geom->base_width = in_geom->base_width;
  2465. geom->base_height = in_geom->base_height;
  2466. geom->aspect_ratio = in_geom->aspect_ratio;
  2467. RARCH_LOG("[Environ]: SET_GEOMETRY: %ux%u, Aspect: %.3f.\n",
  2468. geom->base_width, geom->base_height, geom->aspect_ratio);
  2469. /* Forces recomputation of aspect ratios if
  2470. * using core-dependent aspect ratios. */
  2471. video_driver_set_aspect_ratio();
  2472. /* Ignore frame delay target temporarily */
  2473. if (settings->bools.video_frame_delay_auto)
  2474. video_st->frame_delay_pause = true;
  2475. /* TODO: Figure out what to do, if anything, with
  2476. recording. */
  2477. }
  2478. else
  2479. {
  2480. RARCH_LOG("[Environ]: SET_GEOMETRY.\n");
  2481. }
  2482. break;
  2483. }
  2484. case RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER:
  2485. {
  2486. video_driver_state_t *video_st = video_state_get_ptr();
  2487. struct retro_framebuffer *fb = (struct retro_framebuffer*)data;
  2488. if (
  2489. video_st->poke
  2490. && video_st->poke->get_current_software_framebuffer
  2491. && video_st->poke->get_current_software_framebuffer(
  2492. video_st->data, fb))
  2493. return true;
  2494. return false;
  2495. }
  2496. case RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE:
  2497. {
  2498. video_driver_state_t *video_st = video_state_get_ptr();
  2499. const struct retro_hw_render_interface **iface = (const struct retro_hw_render_interface **)data;
  2500. if (
  2501. video_st->poke
  2502. && video_st->poke->get_hw_render_interface
  2503. && video_st->poke->get_hw_render_interface(
  2504. video_st->data, iface))
  2505. return true;
  2506. return false;
  2507. }
  2508. case RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS:
  2509. #ifdef HAVE_CHEEVOS
  2510. {
  2511. bool state = *(const bool*)data;
  2512. RARCH_LOG("[Environ]: SET_SUPPORT_ACHIEVEMENTS: %s.\n", state ? "yes" : "no");
  2513. rcheevos_set_support_cheevos(state);
  2514. }
  2515. #endif
  2516. break;
  2517. case RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE:
  2518. {
  2519. video_driver_state_t *video_st = video_state_get_ptr();
  2520. const struct retro_hw_render_context_negotiation_interface *iface =
  2521. (const struct retro_hw_render_context_negotiation_interface*)data;
  2522. RARCH_LOG("[Environ]: SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE.\n");
  2523. video_st->hw_render_context_negotiation = iface;
  2524. break;
  2525. }
  2526. case RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS:
  2527. {
  2528. uint64_t *quirks = (uint64_t *) data;
  2529. RARCH_LOG("[Environ]: SET_SERIALIZATION_QUIRKS.\n");
  2530. runloop_st->current_core.serialization_quirks_v = *quirks;
  2531. break;
  2532. }
  2533. case RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT:
  2534. #ifdef HAVE_LIBNX
  2535. RARCH_LOG("[Environ]: SET_HW_SHARED_CONTEXT - ignored for now.\n");
  2536. /* TODO/FIXME - Force this off for now for Switch
  2537. * until shared HW context can work there */
  2538. return false;
  2539. #else
  2540. RARCH_LOG("[Environ]: SET_HW_SHARED_CONTEXT.\n");
  2541. runloop_st->flags |= RUNLOOP_FLAG_CORE_SET_SHARED_CONTEXT;
  2542. #endif
  2543. break;
  2544. case RETRO_ENVIRONMENT_GET_VFS_INTERFACE:
  2545. {
  2546. const uint32_t supported_vfs_version = 3;
  2547. static struct retro_vfs_interface vfs_iface =
  2548. {
  2549. /* VFS API v1 */
  2550. retro_vfs_file_get_path_impl,
  2551. retro_vfs_file_open_impl,
  2552. retro_vfs_file_close_impl,
  2553. retro_vfs_file_size_impl,
  2554. retro_vfs_file_tell_impl,
  2555. retro_vfs_file_seek_impl,
  2556. retro_vfs_file_read_impl,
  2557. retro_vfs_file_write_impl,
  2558. retro_vfs_file_flush_impl,
  2559. retro_vfs_file_remove_impl,
  2560. retro_vfs_file_rename_impl,
  2561. /* VFS API v2 */
  2562. retro_vfs_file_truncate_impl,
  2563. /* VFS API v3 */
  2564. retro_vfs_stat_impl,
  2565. retro_vfs_mkdir_impl,
  2566. retro_vfs_opendir_impl,
  2567. retro_vfs_readdir_impl,
  2568. retro_vfs_dirent_get_name_impl,
  2569. retro_vfs_dirent_is_dir_impl,
  2570. retro_vfs_closedir_impl
  2571. };
  2572. struct retro_vfs_interface_info *vfs_iface_info = (struct retro_vfs_interface_info *) data;
  2573. if (vfs_iface_info->required_interface_version <= supported_vfs_version)
  2574. {
  2575. RARCH_LOG("[Environ]: GET_VFS_INTERFACE. Core requested version >= V%d, providing V%d.\n",
  2576. vfs_iface_info->required_interface_version, supported_vfs_version);
  2577. vfs_iface_info->required_interface_version = supported_vfs_version;
  2578. vfs_iface_info->iface = &vfs_iface;
  2579. system->supports_vfs = true;
  2580. }
  2581. else
  2582. {
  2583. RARCH_WARN("[Environ]: GET_VFS_INTERFACE. Core requested version V%d which is higher than what we support (V%d).\n",
  2584. vfs_iface_info->required_interface_version, supported_vfs_version);
  2585. return false;
  2586. }
  2587. break;
  2588. }
  2589. case RETRO_ENVIRONMENT_GET_LED_INTERFACE:
  2590. {
  2591. struct retro_led_interface *ledintf = (struct retro_led_interface *)data;
  2592. if (ledintf)
  2593. ledintf->set_led_state = led_driver_set_led;
  2594. RARCH_LOG("[Environ]: GET_LED_INTERFACE.\n");
  2595. break;
  2596. }
  2597. case RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE:
  2598. {
  2599. int result = 0;
  2600. video_driver_state_t *video_st = video_state_get_ptr();
  2601. audio_driver_state_t *audio_st = audio_state_get_ptr();
  2602. if ( !(audio_st->flags & AUDIO_FLAG_SUSPENDED)
  2603. && (audio_st->flags & AUDIO_FLAG_ACTIVE))
  2604. result |= 2;
  2605. if ( (video_st->flags & VIDEO_FLAG_ACTIVE)
  2606. && !(video_st->current_video->frame == video_null.frame))
  2607. result |= 1;
  2608. #ifdef HAVE_RUNAHEAD
  2609. if (audio_st->flags & AUDIO_FLAG_HARD_DISABLE)
  2610. result |= 8;
  2611. #endif
  2612. #ifdef HAVE_NETWORKING
  2613. if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_REPLAYING, NULL))
  2614. result &= ~(1|2);
  2615. #endif
  2616. #if defined(HAVE_RUNAHEAD) || defined(HAVE_NETWORKING)
  2617. /* Deprecated.
  2618. Use RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT instead. */
  2619. /* TODO/FIXME: Get rid of this ugly hack. */
  2620. if (runloop_st->flags & RUNLOOP_FLAG_REQUEST_SPECIAL_SAVESTATE)
  2621. result |= 4;
  2622. #endif
  2623. if (data)
  2624. {
  2625. int* result_p = (int*)data;
  2626. *result_p = result;
  2627. }
  2628. break;
  2629. }
  2630. case RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT:
  2631. {
  2632. int result = RETRO_SAVESTATE_CONTEXT_NORMAL;
  2633. #if defined(HAVE_RUNAHEAD) || defined(HAVE_NETWORKING)
  2634. if (runloop_st->flags & RUNLOOP_FLAG_REQUEST_SPECIAL_SAVESTATE)
  2635. {
  2636. #ifdef HAVE_NETWORKING
  2637. if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
  2638. result = RETRO_SAVESTATE_CONTEXT_ROLLBACK_NETPLAY;
  2639. else
  2640. #endif
  2641. {
  2642. #ifdef HAVE_RUNAHEAD
  2643. #if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)
  2644. settings_t *settings = config_get_ptr();
  2645. if ( settings->bools.run_ahead_secondary_instance
  2646. && (runloop_st->flags & RUNLOOP_FLAG_RUNAHEAD_SECONDARY_CORE_AVAILABLE)
  2647. && secondary_core_ensure_exists(runloop_st, settings))
  2648. result = RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_BINARY;
  2649. else
  2650. #endif
  2651. result = RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_INSTANCE;
  2652. #endif
  2653. }
  2654. }
  2655. #endif
  2656. if (data)
  2657. *(int*)data = result;
  2658. break;
  2659. }
  2660. case RETRO_ENVIRONMENT_GET_MIDI_INTERFACE:
  2661. {
  2662. struct retro_midi_interface *midi_interface =
  2663. (struct retro_midi_interface *)data;
  2664. if (midi_interface)
  2665. {
  2666. midi_interface->input_enabled = midi_driver_input_enabled;
  2667. midi_interface->output_enabled = midi_driver_output_enabled;
  2668. midi_interface->read = midi_driver_read;
  2669. midi_interface->write = midi_driver_write;
  2670. midi_interface->flush = midi_driver_flush;
  2671. }
  2672. break;
  2673. }
  2674. case RETRO_ENVIRONMENT_GET_FASTFORWARDING:
  2675. *(bool *)data = ((runloop_st->flags & RUNLOOP_FLAG_FASTMOTION) > 0);
  2676. break;
  2677. case RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE:
  2678. {
  2679. struct retro_fastforwarding_override *fastforwarding_override =
  2680. (struct retro_fastforwarding_override *)data;
  2681. /* Record new retro_fastforwarding_override parameters
  2682. * and schedule application on the the next call of
  2683. * runloop_check_state() */
  2684. if (fastforwarding_override)
  2685. {
  2686. memcpy(&runloop_st->fastmotion_override.next,
  2687. fastforwarding_override,
  2688. sizeof(runloop_st->fastmotion_override.next));
  2689. runloop_st->fastmotion_override.pending = true;
  2690. }
  2691. break;
  2692. }
  2693. case RETRO_ENVIRONMENT_GET_THROTTLE_STATE:
  2694. {
  2695. video_driver_state_t *video_st = video_state_get_ptr();
  2696. audio_driver_state_t *audio_st = audio_state_get_ptr();
  2697. struct retro_throttle_state *throttle_state
  2698. = (struct retro_throttle_state *)data;
  2699. bool menu_opened = false;
  2700. bool core_paused = runloop_st->flags & RUNLOOP_FLAG_PAUSED;
  2701. bool no_audio = ((audio_st->flags & AUDIO_FLAG_SUSPENDED)
  2702. || !(audio_st->flags & AUDIO_FLAG_ACTIVE));
  2703. float core_fps = (float)video_st->av_info.timing.fps;
  2704. #ifdef HAVE_REWIND
  2705. if (runloop_st->rewind_st.flags
  2706. & STATE_MGR_REWIND_ST_FLAG_FRAME_IS_REVERSED)
  2707. {
  2708. throttle_state->mode = RETRO_THROTTLE_REWINDING;
  2709. throttle_state->rate = 0.0f;
  2710. break; /* ignore vsync */
  2711. }
  2712. #endif
  2713. #ifdef HAVE_MENU
  2714. menu_opened = menu_state_get_ptr()->flags & MENU_ST_FLAG_ALIVE;
  2715. if (menu_opened)
  2716. #ifdef HAVE_NETWORKING
  2717. core_paused = settings->bools.menu_pause_libretro &&
  2718. netplay_driver_ctl(RARCH_NETPLAY_CTL_ALLOW_PAUSE, NULL);
  2719. #else
  2720. core_paused = settings->bools.menu_pause_libretro;
  2721. #endif
  2722. #endif
  2723. if (core_paused)
  2724. {
  2725. throttle_state->mode = RETRO_THROTTLE_FRAME_STEPPING;
  2726. throttle_state->rate = 0.0f;
  2727. break; /* ignore vsync */
  2728. }
  2729. /* Base mode and rate. */
  2730. throttle_state->mode = RETRO_THROTTLE_NONE;
  2731. throttle_state->rate = core_fps;
  2732. if (runloop_st->flags & RUNLOOP_FLAG_FASTMOTION)
  2733. {
  2734. throttle_state->mode = RETRO_THROTTLE_FAST_FORWARD;
  2735. throttle_state->rate *= runloop_get_fastforward_ratio(
  2736. settings, &runloop_st->fastmotion_override.current);
  2737. }
  2738. else if ((runloop_st->flags & RUNLOOP_FLAG_SLOWMOTION)
  2739. && !no_audio)
  2740. {
  2741. throttle_state->mode = RETRO_THROTTLE_SLOW_MOTION;
  2742. throttle_state->rate /= (settings->floats.slowmotion_ratio > 0.0f ?
  2743. settings->floats.slowmotion_ratio : 1.0f);
  2744. }
  2745. /* VSync overrides the mode if the rate is limited by the display. */
  2746. if (menu_opened || /* Menu currently always runs with vsync on. */
  2747. ( settings->bools.video_vsync
  2748. && (!(runloop_st->flags & RUNLOOP_FLAG_FORCE_NONBLOCK))
  2749. && !(input_state_get_ptr()->flags & INP_FLAG_NONBLOCKING)))
  2750. {
  2751. float refresh_rate = video_driver_get_refresh_rate();
  2752. if (refresh_rate == 0.0f)
  2753. refresh_rate = settings->floats.video_refresh_rate;
  2754. if (refresh_rate < throttle_state->rate || !throttle_state->rate)
  2755. {
  2756. /* Keep the mode as fast forward even if vsync limits it. */
  2757. if (refresh_rate < core_fps)
  2758. throttle_state->mode = RETRO_THROTTLE_VSYNC;
  2759. throttle_state->rate = refresh_rate;
  2760. }
  2761. }
  2762. /* Special behavior while audio output is not available. */
  2763. if (no_audio && throttle_state->mode != RETRO_THROTTLE_FAST_FORWARD
  2764. && throttle_state->mode != RETRO_THROTTLE_VSYNC)
  2765. {
  2766. /* Keep base if frame limiter matching the core is active. */
  2767. retro_time_t core_limit = (core_fps
  2768. ? (retro_time_t)(1000000.0f / core_fps)
  2769. : (retro_time_t)0);
  2770. retro_time_t frame_limit = runloop_st->frame_limit_minimum_time;
  2771. if (abs((int)(core_limit - frame_limit)) > 10)
  2772. {
  2773. throttle_state->mode = RETRO_THROTTLE_UNBLOCKED;
  2774. throttle_state->rate = 0.0f;
  2775. }
  2776. }
  2777. break;
  2778. }
  2779. case RETRO_ENVIRONMENT_GET_INPUT_BITMASKS:
  2780. /* Just falldown, the function will return true */
  2781. break;
  2782. case RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION:
  2783. RARCH_LOG("[Environ]: GET_CORE_OPTIONS_VERSION.\n");
  2784. /* Current API version is 2 */
  2785. *(unsigned *)data = 2;
  2786. break;
  2787. case RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE:
  2788. {
  2789. /* Try to use the polled refresh rate first. */
  2790. float target_refresh_rate = video_driver_get_refresh_rate();
  2791. /* If the above function failed [possibly because it is not
  2792. * implemented], use the refresh rate set in the config instead. */
  2793. if (target_refresh_rate == 0.0f)
  2794. {
  2795. if (settings)
  2796. target_refresh_rate = settings->floats.video_refresh_rate;
  2797. }
  2798. *(float *)data = target_refresh_rate;
  2799. break;
  2800. }
  2801. case RETRO_ENVIRONMENT_GET_INPUT_MAX_USERS:
  2802. *(unsigned *)data = settings->uints.input_max_users;
  2803. break;
  2804. /* Private environment callbacks.
  2805. *
  2806. * Should all be properly addressed in version 2.
  2807. * */
  2808. case RETRO_ENVIRONMENT_POLL_TYPE_OVERRIDE:
  2809. {
  2810. const unsigned *poll_type_data = (const unsigned*)data;
  2811. if (poll_type_data)
  2812. runloop_st->core_poll_type_override = (enum poll_type_override_t)*poll_type_data;
  2813. }
  2814. break;
  2815. case RETRO_ENVIRONMENT_GET_CLEAR_ALL_THREAD_WAITS_CB:
  2816. *(retro_environment_t *)data = runloop_clear_all_thread_waits;
  2817. break;
  2818. case RETRO_ENVIRONMENT_SET_SAVE_STATE_IN_BACKGROUND:
  2819. {
  2820. bool state = *(const bool*)data;
  2821. RARCH_LOG("[Environ]: SET_SAVE_STATE_IN_BACKGROUND: %s.\n", state ? "yes" : "no");
  2822. set_save_state_in_background(state);
  2823. }
  2824. break;
  2825. case RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE:
  2826. {
  2827. const struct retro_system_content_info_override *overrides =
  2828. (const struct retro_system_content_info_override *)data;
  2829. RARCH_LOG("[Environ]: RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE.\n");
  2830. /* Passing NULL always results in 'success' - this
  2831. * allows cores to test for frontend support of
  2832. * the RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE and
  2833. * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT callbacks */
  2834. if (!overrides)
  2835. return true;
  2836. return content_file_override_set(overrides);
  2837. }
  2838. break;
  2839. case RETRO_ENVIRONMENT_GET_GAME_INFO_EXT:
  2840. {
  2841. content_state_t *p_content =
  2842. content_state_get_ptr();
  2843. const struct retro_game_info_ext **game_info_ext =
  2844. (const struct retro_game_info_ext **)data;
  2845. RARCH_LOG("[Environ]: RETRO_ENVIRONMENT_GET_GAME_INFO_EXT.\n");
  2846. if (!game_info_ext)
  2847. return false;
  2848. if ( p_content
  2849. && p_content->content_list
  2850. && p_content->content_list->game_info_ext)
  2851. *game_info_ext = p_content->content_list->game_info_ext;
  2852. else
  2853. {
  2854. RARCH_ERR("[Environ]: Failed to retrieve extended game info.\n");
  2855. *game_info_ext = NULL;
  2856. return false;
  2857. }
  2858. }
  2859. break;
  2860. case RETRO_ENVIRONMENT_GET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_SUPPORT:
  2861. {
  2862. struct retro_hw_render_context_negotiation_interface *iface =
  2863. (struct retro_hw_render_context_negotiation_interface*)data;
  2864. #ifdef HAVE_VULKAN
  2865. if (iface->interface_type == RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN)
  2866. iface->interface_version = RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION;
  2867. else
  2868. #endif
  2869. {
  2870. iface->interface_version = 0;
  2871. }
  2872. }
  2873. break;
  2874. case RETRO_ENVIRONMENT_GET_JIT_CAPABLE:
  2875. {
  2876. #if defined(HAVE_COCOATOUCH) && TARGET_OS_IOS
  2877. *(bool*)data = jb_has_debugger_attached();
  2878. #else
  2879. *(bool*)data = true;
  2880. #endif
  2881. }
  2882. break;
  2883. default:
  2884. RARCH_LOG("[Environ]: UNSUPPORTED (#%u).\n", cmd);
  2885. return false;
  2886. }
  2887. return true;
  2888. }
  2889. bool libretro_get_system_info(
  2890. const char *path,
  2891. struct retro_system_info *info,
  2892. bool *load_no_content)
  2893. {
  2894. struct retro_system_info dummy_info;
  2895. #ifdef HAVE_DYNAMIC
  2896. dylib_t lib;
  2897. #endif
  2898. runloop_state_t *runloop_st = &runloop_state;
  2899. if (string_ends_with_size(path,
  2900. "builtin", strlen(path), STRLEN_CONST("builtin")))
  2901. return false;
  2902. dummy_info.library_name = NULL;
  2903. dummy_info.library_version = NULL;
  2904. dummy_info.valid_extensions = NULL;
  2905. dummy_info.need_fullpath = false;
  2906. dummy_info.block_extract = false;
  2907. #ifdef HAVE_DYNAMIC
  2908. if (!(lib = libretro_get_system_info_lib(
  2909. path, &dummy_info, load_no_content)))
  2910. {
  2911. RARCH_ERR("%s: \"%s\"\n",
  2912. msg_hash_to_str(MSG_FAILED_TO_OPEN_LIBRETRO_CORE),
  2913. path);
  2914. RARCH_ERR("Error(s): %s\n", dylib_error());
  2915. return false;
  2916. }
  2917. #else
  2918. if (load_no_content)
  2919. {
  2920. runloop_st->load_no_content_hook = load_no_content;
  2921. /* load_no_content gets set in this callback. */
  2922. retro_set_environment(runloop_environ_cb_get_system_info);
  2923. /* It's possible that we just set get_system_info callback
  2924. * to the currently running core.
  2925. *
  2926. * Make sure we reset it to the actual environment callback.
  2927. * Ignore any environment callbacks here in case we're running
  2928. * on the non-current core. */
  2929. runloop_st->flags |= RUNLOOP_FLAG_IGNORE_ENVIRONMENT_CB;
  2930. retro_set_environment(runloop_environment_cb);
  2931. runloop_st->flags &= ~RUNLOOP_FLAG_IGNORE_ENVIRONMENT_CB;
  2932. }
  2933. retro_get_system_info(&dummy_info);
  2934. #endif
  2935. memcpy(info, &dummy_info, sizeof(*info));
  2936. runloop_st->current_library_name[0] = '\0';
  2937. runloop_st->current_library_version[0] = '\0';
  2938. runloop_st->current_valid_extensions[0] = '\0';
  2939. if (!string_is_empty(dummy_info.library_name))
  2940. strlcpy(runloop_st->current_library_name,
  2941. dummy_info.library_name,
  2942. sizeof(runloop_st->current_library_name));
  2943. if (!string_is_empty(dummy_info.library_version))
  2944. strlcpy(runloop_st->current_library_version,
  2945. dummy_info.library_version,
  2946. sizeof(runloop_st->current_library_version));
  2947. if (dummy_info.valid_extensions)
  2948. strlcpy(runloop_st->current_valid_extensions,
  2949. dummy_info.valid_extensions,
  2950. sizeof(runloop_st->current_valid_extensions));
  2951. info->library_name = runloop_st->current_library_name;
  2952. info->library_version = runloop_st->current_library_version;
  2953. info->valid_extensions = runloop_st->current_valid_extensions;
  2954. #ifdef HAVE_DYNAMIC
  2955. dylib_close(lib);
  2956. #endif
  2957. return true;
  2958. }
  2959. bool runloop_init_libretro_symbols(
  2960. void *data,
  2961. enum rarch_core_type type,
  2962. struct retro_core_t *current_core,
  2963. const char *lib_path,
  2964. void *_lib_handle_p)
  2965. {
  2966. #ifdef HAVE_DYNAMIC
  2967. /* the library handle for use with the SYMBOL macro */
  2968. dylib_t lib_handle_local;
  2969. runloop_state_t *runloop_st = (runloop_state_t*)data;
  2970. #endif
  2971. switch (type)
  2972. {
  2973. case CORE_TYPE_PLAIN:
  2974. {
  2975. #ifdef HAVE_DYNAMIC
  2976. #ifdef HAVE_RUNAHEAD
  2977. dylib_t *lib_handle_p = (dylib_t*)_lib_handle_p;
  2978. if (!lib_path || !lib_handle_p)
  2979. #endif
  2980. {
  2981. // bool core_loaded = false;
  2982. const char *path = path_get(RARCH_PATH_CORE);
  2983. // char full_path[PATH_MAX_LENGTH];
  2984. // if (!task_push_core_restore(
  2985. // "/storage/emulated/0/RetroArch/cores/mesen_libretro_android.so",
  2986. // "/data/user/0/com.retroarch.aarch64/cores/",
  2987. // &core_loaded)) {
  2988. // RARCH_ERR("[Core]: Cannot open the dynamic libretro cores.");
  2989. // return false;
  2990. // } else {
  2991. // fill_pathname_join_special(full_path, path, "mesen_libretro_android.so", sizeof(full_path));
  2992. // path_set(RARCH_PATH_CORE, full_path);
  2993. // path = "/data/user/0/com.retroarch.aarch64/cores/mesen_libretro_android.so";
  2994. // }
  2995. // path = path_get(RARCH_PATH_CORE);
  2996. if (string_is_empty(path))
  2997. {
  2998. RARCH_ERR("[Core]: Frontend is built for dynamic libretro cores, but "
  2999. "path is not set. Cannot continue.\n");
  3000. retroarch_fail(1, "init_libretro_symbols()");
  3001. }
  3002. RARCH_LOG("[Core]: Loading dynamic libretro core from: \"%s\"\n",
  3003. path);
  3004. if (!(runloop_st->lib_handle = load_dynamic_core(
  3005. path,
  3006. path_get_ptr(RARCH_PATH_CORE),
  3007. path_get_realsize(RARCH_PATH_CORE)
  3008. )))
  3009. {
  3010. const char *failed_open_str =
  3011. msg_hash_to_str(MSG_FAILED_TO_OPEN_LIBRETRO_CORE);
  3012. RARCH_ERR("%s: \"%s\"\nError(s): %s\n", failed_open_str,
  3013. path, dylib_error());
  3014. runloop_msg_queue_push(failed_open_str,
  3015. 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  3016. return false;
  3017. }
  3018. lib_handle_local = runloop_st->lib_handle;
  3019. }
  3020. #ifdef HAVE_RUNAHEAD
  3021. else
  3022. {
  3023. /* for a secondary core, we already have a
  3024. * primary library loaded, so we can skip
  3025. * some checks and just load the library */
  3026. lib_handle_local = dylib_load(lib_path);
  3027. if (!lib_handle_local)
  3028. return false;
  3029. *lib_handle_p = lib_handle_local;
  3030. }
  3031. #endif
  3032. #endif
  3033. CORE_SYMBOLS(SYMBOL);
  3034. }
  3035. break;
  3036. case CORE_TYPE_DUMMY:
  3037. CORE_SYMBOLS(SYMBOL_DUMMY);
  3038. break;
  3039. case CORE_TYPE_FFMPEG:
  3040. #ifdef HAVE_FFMPEG
  3041. CORE_SYMBOLS(SYMBOL_FFMPEG);
  3042. #endif
  3043. break;
  3044. case CORE_TYPE_MPV:
  3045. #ifdef HAVE_MPV
  3046. CORE_SYMBOLS(SYMBOL_MPV);
  3047. #endif
  3048. break;
  3049. case CORE_TYPE_IMAGEVIEWER:
  3050. #ifdef HAVE_IMAGEVIEWER
  3051. CORE_SYMBOLS(SYMBOL_IMAGEVIEWER);
  3052. #endif
  3053. break;
  3054. case CORE_TYPE_NETRETROPAD:
  3055. #if defined(HAVE_NETWORKING) && defined(HAVE_NETWORKGAMEPAD)
  3056. CORE_SYMBOLS(SYMBOL_NETRETROPAD);
  3057. #endif
  3058. break;
  3059. case CORE_TYPE_VIDEO_PROCESSOR:
  3060. #if defined(HAVE_VIDEOPROCESSOR)
  3061. CORE_SYMBOLS(SYMBOL_VIDEOPROCESSOR);
  3062. #endif
  3063. break;
  3064. }
  3065. return true;
  3066. }
  3067. uint32_t runloop_get_flags(void)
  3068. {
  3069. runloop_state_t *runloop_st = &runloop_state;
  3070. return runloop_st->flags;
  3071. }
  3072. void runloop_system_info_free(void)
  3073. {
  3074. runloop_state_t *runloop_st = &runloop_state;
  3075. rarch_system_info_t *sys_info = &runloop_st->system;
  3076. if (sys_info->subsystem.data)
  3077. free(sys_info->subsystem.data);
  3078. if (sys_info->ports.data)
  3079. free(sys_info->ports.data);
  3080. if (sys_info->mmaps.descriptors)
  3081. free((void *)sys_info->mmaps.descriptors);
  3082. sys_info->subsystem.data = NULL;
  3083. sys_info->subsystem.size = 0;
  3084. sys_info->ports.data = NULL;
  3085. sys_info->ports.size = 0;
  3086. sys_info->mmaps.descriptors = NULL;
  3087. sys_info->mmaps.num_descriptors = 0;
  3088. sys_info->info.library_name = NULL;
  3089. sys_info->info.library_version = NULL;
  3090. sys_info->info.valid_extensions = NULL;
  3091. sys_info->info.need_fullpath = false;
  3092. sys_info->info.block_extract = false;
  3093. runloop_st->key_event = NULL;
  3094. runloop_st->frontend_key_event = NULL;
  3095. memset(&runloop_st->system, 0, sizeof(rarch_system_info_t));
  3096. }
  3097. static void runloop_frame_time_free(runloop_state_t *runloop_st)
  3098. {
  3099. memset(&runloop_st->frame_time, 0,
  3100. sizeof(struct retro_frame_time_callback));
  3101. runloop_st->frame_time_last = 0;
  3102. runloop_st->max_frames = 0;
  3103. }
  3104. static void runloop_audio_buffer_status_free(runloop_state_t *runloop_st)
  3105. {
  3106. memset(&runloop_st->audio_buffer_status, 0,
  3107. sizeof(struct retro_audio_buffer_status_callback));
  3108. runloop_st->audio_latency = 0;
  3109. }
  3110. static void runloop_fastmotion_override_free(runloop_state_t *runloop_st)
  3111. {
  3112. video_driver_state_t
  3113. *video_st = video_state_get_ptr();
  3114. settings_t *settings = config_get_ptr();
  3115. float fastforward_ratio = settings->floats.fastforward_ratio;
  3116. bool reset_frame_limit = runloop_st->fastmotion_override.current.fastforward &&
  3117. (runloop_st->fastmotion_override.current.ratio >= 0.0f) &&
  3118. (runloop_st->fastmotion_override.current.ratio != fastforward_ratio);
  3119. runloop_st->fastmotion_override.current.ratio = 0.0f;
  3120. runloop_st->fastmotion_override.current.fastforward = false;
  3121. runloop_st->fastmotion_override.current.notification = false;
  3122. runloop_st->fastmotion_override.current.inhibit_toggle = false;
  3123. runloop_st->fastmotion_override.next.ratio = 0.0f;
  3124. runloop_st->fastmotion_override.next.fastforward = false;
  3125. runloop_st->fastmotion_override.next.notification = false;
  3126. runloop_st->fastmotion_override.next.inhibit_toggle = false;
  3127. runloop_st->fastmotion_override.pending = false;
  3128. if (reset_frame_limit)
  3129. runloop_set_frame_limit(&video_st->av_info, fastforward_ratio);
  3130. }
  3131. void runloop_state_free(runloop_state_t *runloop_st)
  3132. {
  3133. runloop_frame_time_free(runloop_st);
  3134. runloop_audio_buffer_status_free(runloop_st);
  3135. input_game_focus_free();
  3136. runloop_fastmotion_override_free(runloop_st);
  3137. /* Only a single core options callback is used at present */
  3138. runloop_st->core_options_callback.update_display = NULL;
  3139. runloop_st->video_swap_interval_auto = 1;
  3140. }
  3141. /**
  3142. * uninit_libretro_symbols:
  3143. *
  3144. * Frees libretro core.
  3145. *
  3146. * Frees all core options, associated state, and
  3147. * unbinds all libretro callback symbols.
  3148. **/
  3149. static void uninit_libretro_symbols(
  3150. struct retro_core_t *current_core)
  3151. {
  3152. runloop_state_t *runloop_st = &runloop_state;
  3153. input_driver_state_t *input_st = input_state_get_ptr();
  3154. audio_driver_state_t *audio_st = audio_state_get_ptr();
  3155. camera_driver_state_t *camera_st = camera_state_get_ptr();
  3156. location_driver_state_t *location_st = location_state_get_ptr();
  3157. #ifdef HAVE_DYNAMIC
  3158. if (runloop_st->lib_handle)
  3159. dylib_close(runloop_st->lib_handle);
  3160. runloop_st->lib_handle = NULL;
  3161. #endif
  3162. memset(current_core, 0, sizeof(struct retro_core_t));
  3163. runloop_st->flags &= ~RUNLOOP_FLAG_CORE_SET_SHARED_CONTEXT;
  3164. if (runloop_st->core_options)
  3165. {
  3166. runloop_deinit_core_options(
  3167. runloop_st->flags & RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE,
  3168. path_get(RARCH_PATH_CORE_OPTIONS),
  3169. runloop_st->core_options);
  3170. runloop_st->flags &=
  3171. ~(RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE
  3172. | RUNLOOP_FLAG_FOLDER_OPTIONS_ACTIVE);
  3173. runloop_st->core_options = NULL;
  3174. }
  3175. runloop_system_info_free();
  3176. audio_st->callback.callback = NULL;
  3177. audio_st->callback.set_state = NULL;
  3178. runloop_state_free(runloop_st);
  3179. camera_st->active = false;
  3180. location_st->active = false;
  3181. /* Core has finished utilising the input driver;
  3182. * reset 'analog input requested' flags */
  3183. memset(&input_st->analog_requested, 0,
  3184. sizeof(input_st->analog_requested));
  3185. /* Performance counters no longer valid. */
  3186. runloop_st->perf_ptr_libretro = 0;
  3187. memset(runloop_st->perf_counters_libretro, 0,
  3188. sizeof(runloop_st->perf_counters_libretro));
  3189. }
  3190. static retro_time_t runloop_core_runtime_tick(
  3191. runloop_state_t *runloop_st,
  3192. float slowmotion_ratio,
  3193. retro_time_t current_time)
  3194. {
  3195. video_driver_state_t *video_st = video_state_get_ptr();
  3196. retro_time_t frame_time =
  3197. (1.0 / video_st->av_info.timing.fps) * 1000000;
  3198. bool runloop_slowmotion = runloop_st->flags & RUNLOOP_FLAG_SLOWMOTION;
  3199. bool runloop_fastmotion = runloop_st->flags & RUNLOOP_FLAG_FASTMOTION;
  3200. /* Account for slow motion */
  3201. if (runloop_slowmotion)
  3202. return (retro_time_t)((double)frame_time * slowmotion_ratio);
  3203. /* Account for fast forward */
  3204. if (runloop_fastmotion)
  3205. {
  3206. /* Doing it this way means we miss the first frame after
  3207. * turning fast forward on, but it saves the overhead of
  3208. * having to do:
  3209. * retro_time_t current_usec = cpu_features_get_time_usec();
  3210. * core_runtime_last = current_usec;
  3211. * every frame when fast forward is off. */
  3212. retro_time_t current_usec = current_time;
  3213. retro_time_t potential_frame_time = current_usec -
  3214. runloop_st->core_runtime_last;
  3215. runloop_st->core_runtime_last = current_usec;
  3216. if (potential_frame_time < frame_time)
  3217. return potential_frame_time;
  3218. }
  3219. return frame_time;
  3220. }
  3221. static bool core_unload_game(void)
  3222. {
  3223. runloop_state_t *runloop_st = &runloop_state;
  3224. video_driver_free_hw_context();
  3225. video_driver_set_cached_frame_ptr(NULL);
  3226. if ((runloop_st->current_core.flags & RETRO_CORE_FLAG_GAME_LOADED))
  3227. {
  3228. RARCH_LOG("[Core]: Unloading game..\n");
  3229. runloop_st->current_core.retro_unload_game();
  3230. runloop_st->core_poll_type_override = POLL_TYPE_OVERRIDE_DONTCARE;
  3231. runloop_st->current_core.flags &= ~RETRO_CORE_FLAG_GAME_LOADED;
  3232. }
  3233. audio_driver_stop();
  3234. return true;
  3235. }
  3236. static void runloop_apply_fastmotion_override(runloop_state_t *runloop_st, settings_t *settings)
  3237. {
  3238. float fastforward_ratio_current;
  3239. video_driver_state_t *video_st = video_state_get_ptr();
  3240. bool frame_time_counter_reset_after_fastforwarding = settings ?
  3241. settings->bools.frame_time_counter_reset_after_fastforwarding : false;
  3242. float fastforward_ratio_default = settings ?
  3243. settings->floats.fastforward_ratio : 0.0f;
  3244. float fastforward_ratio_last =
  3245. (runloop_st->fastmotion_override.current.fastforward &&
  3246. (runloop_st->fastmotion_override.current.ratio >= 0.0f)) ?
  3247. runloop_st->fastmotion_override.current.ratio :
  3248. fastforward_ratio_default;
  3249. #if defined(HAVE_GFX_WIDGETS)
  3250. dispgfx_widget_t *p_dispwidget = dispwidget_get_ptr();
  3251. #endif
  3252. memcpy(&runloop_st->fastmotion_override.current,
  3253. &runloop_st->fastmotion_override.next,
  3254. sizeof(runloop_st->fastmotion_override.current));
  3255. /* Check if 'fastmotion' state has changed */
  3256. if (((runloop_st->flags & RUNLOOP_FLAG_FASTMOTION) > 0) !=
  3257. runloop_st->fastmotion_override.current.fastforward)
  3258. {
  3259. input_driver_state_t *input_st = input_state_get_ptr();
  3260. if (runloop_st->fastmotion_override.current.fastforward)
  3261. runloop_st->flags |= RUNLOOP_FLAG_FASTMOTION;
  3262. else
  3263. runloop_st->flags &= ~RUNLOOP_FLAG_FASTMOTION;
  3264. if (input_st)
  3265. {
  3266. if (runloop_st->flags & RUNLOOP_FLAG_FASTMOTION)
  3267. input_st->flags |= INP_FLAG_NONBLOCKING;
  3268. else
  3269. input_st->flags &= ~INP_FLAG_NONBLOCKING;
  3270. }
  3271. if (!(runloop_st->flags & RUNLOOP_FLAG_FASTMOTION))
  3272. runloop_st->fastforward_after_frames = 1;
  3273. driver_set_nonblock_state();
  3274. /* Reset frame time counter when toggling
  3275. * fast-forward off, if required */
  3276. if ( !(runloop_st->flags & RUNLOOP_FLAG_FASTMOTION)
  3277. && frame_time_counter_reset_after_fastforwarding)
  3278. video_st->frame_time_count = 0;
  3279. /* Ensure fast forward widget is disabled when
  3280. * toggling fast-forward off
  3281. * (required if RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE
  3282. * is called during core de-initialisation) */
  3283. #if defined(HAVE_GFX_WIDGETS)
  3284. if ( p_dispwidget->active
  3285. && !(runloop_st->flags & RUNLOOP_FLAG_FASTMOTION))
  3286. video_st->flags &= ~VIDEO_FLAG_WIDGETS_FAST_FORWARD;
  3287. #endif
  3288. }
  3289. /* Update frame limit, if required */
  3290. fastforward_ratio_current = (runloop_st->fastmotion_override.current.fastforward &&
  3291. (runloop_st->fastmotion_override.current.ratio >= 0.0f)) ?
  3292. runloop_st->fastmotion_override.current.ratio :
  3293. fastforward_ratio_default;
  3294. if (fastforward_ratio_current != fastforward_ratio_last)
  3295. runloop_set_frame_limit(&video_st->av_info,
  3296. fastforward_ratio_current);
  3297. }
  3298. void runloop_event_deinit_core(void)
  3299. {
  3300. video_driver_state_t
  3301. *video_st = video_state_get_ptr();
  3302. runloop_state_t *runloop_st = &runloop_state;
  3303. settings_t *settings = config_get_ptr();
  3304. core_unload_game();
  3305. video_driver_set_cached_frame_ptr(NULL);
  3306. if (runloop_st->current_core.flags & RETRO_CORE_FLAG_INITED)
  3307. {
  3308. RARCH_LOG("[Core]: Unloading core..\n");
  3309. runloop_st->current_core.retro_deinit();
  3310. }
  3311. /* retro_deinit() may call
  3312. * RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE
  3313. * (i.e. to ensure that fastforwarding is
  3314. * disabled on core close)
  3315. * > Check for any pending updates */
  3316. if (runloop_st->fastmotion_override.pending)
  3317. {
  3318. runloop_apply_fastmotion_override(runloop_st,
  3319. settings);
  3320. runloop_st->fastmotion_override.pending = false;
  3321. }
  3322. if ( (runloop_st->flags & RUNLOOP_FLAG_REMAPS_CORE_ACTIVE)
  3323. || (runloop_st->flags & RUNLOOP_FLAG_REMAPS_CONTENT_DIR_ACTIVE)
  3324. || (runloop_st->flags & RUNLOOP_FLAG_REMAPS_GAME_ACTIVE)
  3325. || !string_is_empty(runloop_st->name.remapfile)
  3326. )
  3327. {
  3328. input_remapping_deinit(settings->bools.remap_save_on_exit);
  3329. input_remapping_set_defaults(true);
  3330. }
  3331. else
  3332. input_remapping_restore_global_config(true);
  3333. RARCH_LOG("[Core]: Unloading core symbols..\n");
  3334. uninit_libretro_symbols(&runloop_st->current_core);
  3335. runloop_st->current_core.flags &= ~RETRO_CORE_FLAG_SYMBOLS_INITED;
  3336. /* Restore original refresh rate, if it has been changed
  3337. * automatically in SET_SYSTEM_AV_INFO */
  3338. if (video_st->video_refresh_rate_original)
  3339. {
  3340. /* Set the av_info fps also to the original refresh rate */
  3341. /* to avoid re-initialization problems */
  3342. struct retro_system_av_info *av_info = &video_st->av_info;
  3343. av_info->timing.fps = video_st->video_refresh_rate_original;
  3344. video_display_server_restore_refresh_rate();
  3345. }
  3346. /* Recalibrate frame delay target */
  3347. if (settings->bools.video_frame_delay_auto)
  3348. video_st->frame_delay_target = 0;
  3349. driver_uninit(DRIVERS_CMD_ALL);
  3350. #ifdef HAVE_CONFIGFILE
  3351. if (runloop_st->flags & RUNLOOP_FLAG_OVERRIDES_ACTIVE)
  3352. {
  3353. /* Reload the original config */
  3354. config_unload_override();
  3355. }
  3356. #endif
  3357. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  3358. runloop_st->runtime_shader_preset_path[0] = '\0';
  3359. #endif
  3360. }
  3361. static bool runloop_path_init_subsystem(runloop_state_t *runloop_st)
  3362. {
  3363. unsigned i, j;
  3364. const struct retro_subsystem_info *info = NULL;
  3365. rarch_system_info_t *system = &runloop_st->system;
  3366. bool subsystem_path_empty = path_is_empty(RARCH_PATH_SUBSYSTEM);
  3367. const char *savefile_dir = runloop_st->savefile_dir;
  3368. if (!system || subsystem_path_empty)
  3369. return false;
  3370. /* For subsystems, we know exactly which RAM types are supported. */
  3371. /* We'll handle this error gracefully later. */
  3372. if ((info = libretro_find_subsystem_info(
  3373. system->subsystem.data,
  3374. system->subsystem.size,
  3375. path_get(RARCH_PATH_SUBSYSTEM))))
  3376. {
  3377. unsigned num_content = MIN(info->num_roms,
  3378. subsystem_path_empty ?
  3379. 0 : (unsigned)runloop_st->subsystem_fullpaths->size);
  3380. for (i = 0; i < num_content; i++)
  3381. {
  3382. for (j = 0; j < info->roms[i].num_memory; j++)
  3383. {
  3384. char ext[32];
  3385. union string_list_elem_attr attr;
  3386. char savename[PATH_MAX_LENGTH];
  3387. char path[PATH_MAX_LENGTH];
  3388. const struct retro_subsystem_memory_info *mem =
  3389. (const struct retro_subsystem_memory_info*)
  3390. &info->roms[i].memory[j];
  3391. ext[0] = '.';
  3392. ext[1] = '\0';
  3393. strlcat(ext, mem->extension, sizeof(ext));
  3394. strlcpy(savename,
  3395. runloop_st->subsystem_fullpaths->elems[i].data,
  3396. sizeof(savename));
  3397. path_remove_extension(savename);
  3398. if (path_is_directory(savefile_dir))
  3399. {
  3400. /* Use SRAM dir */
  3401. /* Redirect content fullpath to save directory. */
  3402. strlcpy(path, savefile_dir, sizeof(path));
  3403. fill_pathname_dir(path, savename, ext, sizeof(path));
  3404. }
  3405. else
  3406. fill_pathname(path, savename, ext, sizeof(path));
  3407. RARCH_LOG("%s \"%s\".\n",
  3408. msg_hash_to_str(MSG_REDIRECTING_SAVEFILE_TO),
  3409. path);
  3410. attr.i = mem->type;
  3411. string_list_append((struct string_list*)savefile_ptr_get(),
  3412. path, attr);
  3413. }
  3414. }
  3415. }
  3416. /* Let other relevant paths be inferred
  3417. from the main SRAM location. */
  3418. if (!retroarch_override_setting_is_set(
  3419. RARCH_OVERRIDE_SETTING_SAVE_PATH, NULL))
  3420. {
  3421. size_t len = strlcpy(runloop_st->name.savefile,
  3422. runloop_st->runtime_content_path_basename,
  3423. sizeof(runloop_st->name.savefile));
  3424. runloop_st->name.savefile[len ] = '.';
  3425. runloop_st->name.savefile[len+1] = 's';
  3426. runloop_st->name.savefile[len+2] = 'r';
  3427. runloop_st->name.savefile[len+3] = 'm';
  3428. runloop_st->name.savefile[len+4] = '\0';
  3429. }
  3430. if (path_is_directory(runloop_st->name.savefile))
  3431. {
  3432. fill_pathname_dir(runloop_st->name.savefile,
  3433. runloop_st->runtime_content_path_basename,
  3434. ".srm",
  3435. sizeof(runloop_st->name.savefile));
  3436. RARCH_LOG("%s \"%s\".\n",
  3437. msg_hash_to_str(MSG_REDIRECTING_SAVEFILE_TO),
  3438. runloop_st->name.savefile);
  3439. }
  3440. return true;
  3441. }
  3442. static void runloop_path_init_savefile_internal(runloop_state_t *runloop_st)
  3443. {
  3444. path_deinit_savefile();
  3445. path_init_savefile_new();
  3446. if (!runloop_path_init_subsystem(runloop_st))
  3447. path_init_savefile_rtc(runloop_st->name.savefile);
  3448. }
  3449. static void runloop_path_init_savefile(runloop_state_t *runloop_st)
  3450. {
  3451. bool should_sram_be_used =
  3452. (runloop_st->flags & RUNLOOP_FLAG_USE_SRAM)
  3453. && !(runloop_st->flags & RUNLOOP_FLAG_IS_SRAM_SAVE_DISABLED);
  3454. if (should_sram_be_used)
  3455. runloop_st->flags |= RUNLOOP_FLAG_USE_SRAM;
  3456. else
  3457. runloop_st->flags &= ~RUNLOOP_FLAG_USE_SRAM;
  3458. if (!(runloop_st->flags & RUNLOOP_FLAG_USE_SRAM))
  3459. {
  3460. RARCH_LOG("[SRAM]: %s\n",
  3461. msg_hash_to_str(MSG_SRAM_WILL_NOT_BE_SAVED));
  3462. return;
  3463. }
  3464. command_event(CMD_EVENT_AUTOSAVE_INIT, NULL);
  3465. }
  3466. static bool event_init_content(
  3467. runloop_state_t *runloop_st,
  3468. settings_t *settings,
  3469. input_driver_state_t *input_st)
  3470. {
  3471. #ifdef HAVE_CHEEVOS
  3472. bool cheevos_enable =
  3473. settings->bools.cheevos_enable;
  3474. bool cheevos_hardcore_mode_enable =
  3475. settings->bools.cheevos_hardcore_mode_enable;
  3476. #endif
  3477. const enum rarch_core_type current_core_type = runloop_st->current_core_type;
  3478. uint8_t flags = content_get_flags();
  3479. if (current_core_type == CORE_TYPE_PLAIN)
  3480. runloop_st->flags |= RUNLOOP_FLAG_USE_SRAM;
  3481. else
  3482. runloop_st->flags &= ~RUNLOOP_FLAG_USE_SRAM;
  3483. /* No content to be loaded for dummy core,
  3484. * just successfully exit. */
  3485. if (current_core_type == CORE_TYPE_DUMMY)
  3486. return true;
  3487. content_set_subsystem_info();
  3488. /* If core is contentless, just initialise SRAM
  3489. * interface, otherwise fill all content-related
  3490. * paths */
  3491. if (flags & CONTENT_ST_FLAG_CORE_DOES_NOT_NEED_CONTENT)
  3492. runloop_path_init_savefile_internal(runloop_st);
  3493. else
  3494. runloop_path_fill_names();
  3495. if (!content_init())
  3496. return false;
  3497. command_event_set_savestate_auto_index(settings);
  3498. command_event_set_replay_auto_index(settings);
  3499. runloop_path_init_savefile(runloop_st);
  3500. if (!event_load_save_files(runloop_st->flags &
  3501. RUNLOOP_FLAG_IS_SRAM_LOAD_DISABLED))
  3502. RARCH_LOG("[SRAM]: %s\n",
  3503. msg_hash_to_str(MSG_SKIPPING_SRAM_LOAD));
  3504. /*
  3505. Since the operations are asynchronous we can't
  3506. guarantee users will not use auto_load_state to cheat on
  3507. achievements so we forbid auto_load_state from happening
  3508. if cheevos_enable and cheevos_hardcode_mode_enable
  3509. are true.
  3510. */
  3511. #ifdef HAVE_CHEEVOS
  3512. if (!cheevos_enable || !cheevos_hardcore_mode_enable)
  3513. #endif
  3514. {
  3515. #ifdef HAVE_BSV_MOVIE
  3516. /* ignore entry state if we're doing bsv playback (we do want it
  3517. for bsv recording though) */
  3518. if (!(input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_START_PLAYBACK))
  3519. #endif
  3520. {
  3521. if (runloop_st->entry_state_slot && !command_event_load_entry_state(settings))
  3522. {
  3523. /* loading the state failed, reset entry slot */
  3524. runloop_st->entry_state_slot = 0;
  3525. }
  3526. }
  3527. #ifdef HAVE_BSV_MOVIE
  3528. /* ignore autoload state if we're doing bsv playback or recording */
  3529. if (!(input_st->bsv_movie_state.flags & (BSV_FLAG_MOVIE_START_RECORDING | BSV_FLAG_MOVIE_START_PLAYBACK)))
  3530. #endif
  3531. {
  3532. if (!runloop_st->entry_state_slot && settings->bools.savestate_auto_load)
  3533. command_event_load_auto_state();
  3534. }
  3535. }
  3536. #ifdef HAVE_BSV_MOVIE
  3537. movie_stop(input_st);
  3538. if (input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_START_RECORDING)
  3539. {
  3540. configuration_set_uint(settings, settings->uints.rewind_granularity, 1);
  3541. #ifndef HAVE_THREADS
  3542. /* Hack: the regular scheduler doesn't do the right thing here at
  3543. least in emscripten builds. I would expect that the check in
  3544. task_movie.c:343 should defer recording until the movie task
  3545. is done, but maybe that task isn't enqueued again yet when the
  3546. movie-record task is checked? Or the finder call in
  3547. content_load_state_in_progress is not correct? Either way,
  3548. the load happens after the recording starts rather than the
  3549. right way around.
  3550. */
  3551. task_queue_wait(NULL,NULL);
  3552. #endif
  3553. movie_start_record(input_st, input_st->bsv_movie_state.movie_start_path);
  3554. }
  3555. else if (input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_START_PLAYBACK)
  3556. {
  3557. configuration_set_uint(settings, settings->uints.rewind_granularity, 1);
  3558. movie_start_playback(input_st, input_st->bsv_movie_state.movie_start_path);
  3559. }
  3560. #endif
  3561. command_event(CMD_EVENT_NETPLAY_INIT, NULL);
  3562. return true;
  3563. }
  3564. static void runloop_runtime_log_init(runloop_state_t *runloop_st)
  3565. {
  3566. const char *content_path = path_get(RARCH_PATH_CONTENT);
  3567. const char *core_path = path_get(RARCH_PATH_CORE);
  3568. runloop_st->core_runtime_last = cpu_features_get_time_usec();
  3569. runloop_st->core_runtime_usec = 0;
  3570. /* Have to cache content and core path here, otherwise
  3571. * logging fails if new content is loaded without
  3572. * closing existing content
  3573. * i.e. RARCH_PATH_CONTENT and RARCH_PATH_CORE get
  3574. * updated when the new content is loaded, which
  3575. * happens *before* command_event_runtime_log_deinit
  3576. * -> using RARCH_PATH_CONTENT and RARCH_PATH_CORE
  3577. * directly in command_event_runtime_log_deinit
  3578. * can therefore lead to the runtime of the currently
  3579. * loaded content getting written to the *new*
  3580. * content's log file... */
  3581. memset(runloop_st->runtime_content_path,
  3582. 0, sizeof(runloop_st->runtime_content_path));
  3583. memset(runloop_st->runtime_core_path,
  3584. 0, sizeof(runloop_st->runtime_core_path));
  3585. if (!string_is_empty(content_path))
  3586. strlcpy(runloop_st->runtime_content_path,
  3587. content_path,
  3588. sizeof(runloop_st->runtime_content_path));
  3589. if (!string_is_empty(core_path))
  3590. strlcpy(runloop_st->runtime_core_path,
  3591. core_path,
  3592. sizeof(runloop_st->runtime_core_path));
  3593. }
  3594. void runloop_set_frame_limit(
  3595. const struct retro_system_av_info *av_info,
  3596. float fastforward_ratio)
  3597. {
  3598. runloop_state_t *runloop_st = &runloop_state;
  3599. if (fastforward_ratio < 1.0f)
  3600. runloop_st->frame_limit_minimum_time = 0.0f;
  3601. else
  3602. runloop_st->frame_limit_minimum_time = (retro_time_t)
  3603. roundf(1000000.0f /
  3604. (av_info->timing.fps * fastforward_ratio));
  3605. }
  3606. float runloop_get_fastforward_ratio(
  3607. settings_t *settings,
  3608. struct retro_fastforwarding_override *fastmotion_override)
  3609. {
  3610. if ( fastmotion_override->fastforward
  3611. && (fastmotion_override->ratio >= 0.0f))
  3612. return fastmotion_override->ratio;
  3613. return settings->floats.fastforward_ratio;
  3614. }
  3615. void runloop_set_video_swap_interval(
  3616. bool vrr_runloop_enable,
  3617. bool crt_switching_active,
  3618. unsigned swap_interval_config,
  3619. float audio_max_timing_skew,
  3620. float video_refresh_rate,
  3621. double input_fps)
  3622. {
  3623. runloop_state_t *runloop_st = &runloop_state;
  3624. float core_hz = input_fps;
  3625. float timing_hz = crt_switching_active ?
  3626. input_fps : video_refresh_rate;
  3627. float swap_ratio;
  3628. unsigned swap_integer;
  3629. float timing_skew;
  3630. /* If automatic swap interval selection is
  3631. * disabled, just record user-set value */
  3632. if (swap_interval_config != 0)
  3633. {
  3634. runloop_st->video_swap_interval_auto =
  3635. swap_interval_config;
  3636. return;
  3637. }
  3638. /* > If VRR is enabled, swap interval is irrelevant,
  3639. * just set to 1
  3640. * > If core fps is higher than display refresh rate,
  3641. * set swap interval to 1
  3642. * > If core fps or display refresh rate are zero,
  3643. * set swap interval to 1 */
  3644. if ( (vrr_runloop_enable)
  3645. || (core_hz > timing_hz)
  3646. || (core_hz <= 0.0f)
  3647. || (timing_hz <= 0.0f))
  3648. {
  3649. runloop_st->video_swap_interval_auto = 1;
  3650. return;
  3651. }
  3652. /* Check whether display refresh rate is an integer
  3653. * multiple of core fps (within timing skew tolerance) */
  3654. swap_ratio = timing_hz / core_hz;
  3655. swap_integer = (unsigned)(swap_ratio + 0.5f);
  3656. /* > Sanity check: swap interval must be in the
  3657. * range [1,4] - if we are outside this, then
  3658. * bail... */
  3659. if ((swap_integer < 1) || (swap_integer > 4))
  3660. {
  3661. runloop_st->video_swap_interval_auto = 1;
  3662. return;
  3663. }
  3664. timing_skew = fabs(1.0f - core_hz / (timing_hz / (float)swap_integer));
  3665. runloop_st->video_swap_interval_auto =
  3666. (timing_skew <= audio_max_timing_skew) ?
  3667. swap_integer : 1;
  3668. }
  3669. unsigned runloop_get_video_swap_interval(
  3670. unsigned swap_interval_config)
  3671. {
  3672. runloop_state_t *runloop_st = &runloop_state;
  3673. return (swap_interval_config == 0) ?
  3674. runloop_st->video_swap_interval_auto :
  3675. swap_interval_config;
  3676. }
  3677. /*
  3678. Returns rotation requested by the core regardless of if it has been
  3679. applied with the final video rotation
  3680. */
  3681. unsigned int retroarch_get_core_requested_rotation(void)
  3682. {
  3683. return runloop_state.system.core_requested_rotation;
  3684. }
  3685. /*
  3686. Returns final rotation including both user chosen video rotation
  3687. and core requested rotation if allowed by video_allow_rotate
  3688. */
  3689. unsigned int retroarch_get_rotation(void)
  3690. {
  3691. settings_t *settings = config_get_ptr();
  3692. return settings->uints.video_rotation + runloop_state.system.rotation;
  3693. }
  3694. static void retro_run_null(void) { } /* Stub function callback impl. */
  3695. static bool core_verify_api_version(runloop_state_t *runloop_st)
  3696. {
  3697. unsigned api_version = runloop_st->current_core.retro_api_version();
  3698. if (api_version != RETRO_API_VERSION)
  3699. {
  3700. RARCH_WARN("[Core]: %s\n", msg_hash_to_str(MSG_LIBRETRO_ABI_BREAK));
  3701. return false;
  3702. }
  3703. RARCH_LOG("[Core]: %s: %u, %s: %u\n",
  3704. msg_hash_to_str(MSG_VERSION_OF_LIBRETRO_API),
  3705. api_version,
  3706. msg_hash_to_str(MSG_COMPILED_AGAINST_API),
  3707. RETRO_API_VERSION
  3708. );
  3709. return true;
  3710. }
  3711. static int16_t core_input_state_poll_late(unsigned port,
  3712. unsigned device, unsigned idx, unsigned id)
  3713. {
  3714. runloop_state_t *runloop_st = &runloop_state;
  3715. if (!(runloop_st->current_core.flags & RETRO_CORE_FLAG_INPUT_POLLED))
  3716. input_driver_poll();
  3717. runloop_st->current_core.flags |= RETRO_CORE_FLAG_INPUT_POLLED;
  3718. return input_driver_state_wrapper(port, device, idx, id);
  3719. }
  3720. static void core_input_state_poll_maybe(void)
  3721. {
  3722. runloop_state_t *runloop_st = &runloop_state;
  3723. const enum poll_type_override_t
  3724. core_poll_type_override = runloop_st->core_poll_type_override;
  3725. unsigned new_poll_type = (core_poll_type_override > POLL_TYPE_OVERRIDE_DONTCARE)
  3726. ? (core_poll_type_override - 1)
  3727. : runloop_st->current_core.poll_type;
  3728. if (new_poll_type == POLL_TYPE_NORMAL)
  3729. input_driver_poll();
  3730. }
  3731. static retro_input_state_t core_input_state_poll_return_cb(void)
  3732. {
  3733. runloop_state_t *runloop_st = &runloop_state;
  3734. const enum poll_type_override_t
  3735. core_poll_type_override = runloop_st->core_poll_type_override;
  3736. unsigned new_poll_type = (core_poll_type_override > POLL_TYPE_OVERRIDE_DONTCARE)
  3737. ? (core_poll_type_override - 1)
  3738. : runloop_st->current_core.poll_type;
  3739. if (new_poll_type == POLL_TYPE_LATE)
  3740. return core_input_state_poll_late;
  3741. return input_driver_state_wrapper;
  3742. }
  3743. /**
  3744. * core_init_libretro_cbs:
  3745. * @data : pointer to retro_callbacks object
  3746. *
  3747. * Initializes libretro callbacks, and binds the libretro callbacks
  3748. * to default callback functions.
  3749. **/
  3750. static void core_init_libretro_cbs(runloop_state_t *runloop_st,
  3751. struct retro_callbacks *cbs)
  3752. {
  3753. retro_input_state_t state_cb = core_input_state_poll_return_cb();
  3754. runloop_st->current_core.retro_set_video_refresh(video_driver_frame);
  3755. runloop_st->current_core.retro_set_audio_sample(audio_driver_sample);
  3756. runloop_st->current_core.retro_set_audio_sample_batch(audio_driver_sample_batch);
  3757. runloop_st->current_core.retro_set_input_state(state_cb);
  3758. runloop_st->current_core.retro_set_input_poll(core_input_state_poll_maybe);
  3759. runloop_st->input_poll_callback_original = core_input_state_poll_maybe;
  3760. core_set_default_callbacks(cbs);
  3761. #ifdef HAVE_NETWORKING
  3762. if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL))
  3763. core_set_netplay_callbacks();
  3764. #endif
  3765. }
  3766. static bool runloop_event_load_core(runloop_state_t *runloop_st,
  3767. unsigned poll_type_behavior)
  3768. {
  3769. video_driver_state_t *video_st = video_state_get_ptr();
  3770. runloop_st->current_core.poll_type = poll_type_behavior;
  3771. if (!core_verify_api_version(runloop_st))
  3772. return false;
  3773. core_init_libretro_cbs(runloop_st, &runloop_st->retro_ctx);
  3774. runloop_st->current_core.retro_get_system_av_info(&video_st->av_info);
  3775. video_st->core_frame_time = 1000000 /
  3776. ((video_st->av_info.timing.fps > 0.0) ?
  3777. video_st->av_info.timing.fps : 60.0);
  3778. return true;
  3779. }
  3780. bool runloop_event_init_core(
  3781. settings_t *settings,
  3782. void *input_data,
  3783. enum rarch_core_type type,
  3784. const char *old_savefile_dir,
  3785. const char *old_savestate_dir)
  3786. {
  3787. size_t len;
  3788. runloop_state_t *runloop_st = &runloop_state;
  3789. input_driver_state_t *input_st = (input_driver_state_t*)input_data;
  3790. video_driver_state_t *video_st = video_state_get_ptr();
  3791. #ifdef HAVE_CONFIGFILE
  3792. bool auto_overrides_enable = settings->bools.auto_overrides_enable;
  3793. bool auto_remaps_enable = false;
  3794. const char *dir_input_remapping = NULL;
  3795. #endif
  3796. bool show_set_initial_disk_msg = false;
  3797. unsigned poll_type_behavior = 0;
  3798. float fastforward_ratio = 0.0f;
  3799. rarch_system_info_t *sys_info = &runloop_st->system;
  3800. #ifdef HAVE_NETWORKING
  3801. if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
  3802. {
  3803. #ifdef HAVE_UPDATE_CORES
  3804. /* If netplay is enabled, update the core before initializing. */
  3805. const char *path_core = path_get(RARCH_PATH_CORE);
  3806. if (!string_is_empty(path_core) &&
  3807. !string_is_equal(path_core, "builtin"))
  3808. {
  3809. if (task_push_update_single_core(path_core,
  3810. settings->bools.core_updater_auto_backup,
  3811. settings->uints.core_updater_auto_backup_history_size,
  3812. settings->paths.directory_libretro,
  3813. settings->paths.directory_core_assets))
  3814. /* We must wait for the update to finish
  3815. before starting the core. */
  3816. task_queue_wait(NULL, NULL);
  3817. }
  3818. #endif
  3819. /* We need this in order for core_info_current_supports_netplay
  3820. to work correctly at init_netplay,
  3821. called later at event_init_content. */
  3822. command_event(CMD_EVENT_CORE_INFO_INIT, NULL);
  3823. command_event(CMD_EVENT_LOAD_CORE_PERSIST, NULL);
  3824. }
  3825. #endif
  3826. /* Load symbols */
  3827. if (!runloop_init_libretro_symbols(runloop_st,
  3828. type, &runloop_st->current_core, NULL, NULL))
  3829. return false;
  3830. #ifdef HAVE_RUNAHEAD
  3831. /* remember last core type created, so creating a
  3832. * secondary core will know what core type to use. */
  3833. runloop_st->last_core_type = type;
  3834. #endif
  3835. if (!runloop_st->current_core.retro_run)
  3836. runloop_st->current_core.retro_run = retro_run_null;
  3837. runloop_st->current_core.flags |= RETRO_CORE_FLAG_SYMBOLS_INITED;
  3838. runloop_st->current_core.retro_get_system_info(&sys_info->info);
  3839. if (!sys_info->info.library_name)
  3840. sys_info->info.library_name = msg_hash_to_str(MSG_UNKNOWN);
  3841. if (!sys_info->info.library_version)
  3842. sys_info->info.library_version = "v0";
  3843. len = strlcpy(
  3844. video_st->title_buf,
  3845. msg_hash_to_str(MSG_PROGRAM),
  3846. sizeof(video_st->title_buf));
  3847. video_st->title_buf[len ] = ' ';
  3848. video_st->title_buf[len+1] = '\0';
  3849. len = strlcat(video_st->title_buf,
  3850. sys_info->info.library_name,
  3851. sizeof(video_st->title_buf));
  3852. video_st->title_buf[len ] = ' ';
  3853. video_st->title_buf[len+1] = '\0';
  3854. strlcat(video_st->title_buf,
  3855. sys_info->info.library_version,
  3856. sizeof(video_st->title_buf));
  3857. strlcpy(sys_info->valid_extensions,
  3858. sys_info->info.valid_extensions ?
  3859. sys_info->info.valid_extensions : DEFAULT_EXT,
  3860. sizeof(sys_info->valid_extensions));
  3861. #ifdef HAVE_CONFIGFILE
  3862. if (auto_overrides_enable)
  3863. config_load_override(&runloop_st->system);
  3864. #endif
  3865. /* Cannot access these settings-related parameters
  3866. * until *after* config overrides have been loaded */
  3867. #ifdef HAVE_CONFIGFILE
  3868. auto_remaps_enable = settings->bools.auto_remaps_enable;
  3869. dir_input_remapping = settings->paths.directory_input_remapping;
  3870. #endif
  3871. show_set_initial_disk_msg = settings->bools.notification_show_set_initial_disk;
  3872. poll_type_behavior = settings->uints.input_poll_type_behavior;
  3873. fastforward_ratio = runloop_get_fastforward_ratio(
  3874. settings, &runloop_st->fastmotion_override.current);
  3875. #ifdef HAVE_CHEEVOS
  3876. /* assume the core supports achievements unless it tells us otherwise */
  3877. rcheevos_set_support_cheevos(true);
  3878. #endif
  3879. /* Load auto-shaders on the next occasion */
  3880. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  3881. video_st->flags |= VIDEO_FLAG_SHADER_PRESETS_NEED_RELOAD;
  3882. runloop_st->shader_delay_timer.timer_begin = false; /* not initialized */
  3883. runloop_st->shader_delay_timer.timer_end = false; /* not expired */
  3884. #endif
  3885. /* reset video format to libretro's default */
  3886. video_st->pix_fmt = RETRO_PIXEL_FORMAT_0RGB1555;
  3887. runloop_st->current_core.retro_set_environment(runloop_environment_cb);
  3888. /* Load any input remap files
  3889. * > Note that we always cache the current global
  3890. * input settings when initialising a core
  3891. * (regardless of whether remap files are loaded)
  3892. * so settings can be restored when the core is
  3893. * unloaded - i.e. core remapping options modified
  3894. * at runtime should not 'bleed through' into the
  3895. * master config file */
  3896. input_remapping_cache_global_config();
  3897. #ifdef HAVE_CONFIGFILE
  3898. if (auto_remaps_enable)
  3899. config_load_remap(dir_input_remapping, &runloop_st->system);
  3900. #endif
  3901. /* Per-core saves: reset redirection paths */
  3902. runloop_path_set_redirect(settings, old_savefile_dir, old_savestate_dir);
  3903. video_driver_set_cached_frame_ptr(NULL);
  3904. runloop_st->current_core.retro_init();
  3905. runloop_st->current_core.flags |= RETRO_CORE_FLAG_INITED;
  3906. /* Attempt to set initial disk index */
  3907. disk_control_set_initial_index(
  3908. &sys_info->disk_control,
  3909. path_get(RARCH_PATH_CONTENT),
  3910. runloop_st->savefile_dir);
  3911. if (!event_init_content(runloop_st, settings, input_st))
  3912. {
  3913. runloop_st->flags &= ~RUNLOOP_FLAG_CORE_RUNNING;
  3914. return false;
  3915. }
  3916. /* Verify that initial disk index was set correctly */
  3917. disk_control_verify_initial_index(&sys_info->disk_control,
  3918. show_set_initial_disk_msg);
  3919. if (!runloop_event_load_core(runloop_st, poll_type_behavior))
  3920. return false;
  3921. runloop_set_frame_limit(&video_st->av_info, fastforward_ratio);
  3922. runloop_st->frame_limit_last_time = cpu_features_get_time_usec();
  3923. runloop_runtime_log_init(runloop_st);
  3924. return true;
  3925. }
  3926. void runloop_pause_checks(void)
  3927. {
  3928. #ifdef HAVE_PRESENCE
  3929. presence_userdata_t userdata;
  3930. #endif
  3931. runloop_state_t *runloop_st = &runloop_state;
  3932. bool is_paused = runloop_st->flags & RUNLOOP_FLAG_PAUSED;
  3933. bool is_idle = runloop_st->flags & RUNLOOP_FLAG_IDLE;
  3934. #if defined(HAVE_GFX_WIDGETS)
  3935. video_driver_state_t *video_st = video_state_get_ptr();
  3936. dispgfx_widget_t *p_dispwidget = dispwidget_get_ptr();
  3937. bool widgets_active = p_dispwidget->active;
  3938. if (widgets_active)
  3939. {
  3940. if (is_paused)
  3941. video_st->flags |= VIDEO_FLAG_WIDGETS_PAUSED;
  3942. else
  3943. video_st->flags &= ~VIDEO_FLAG_WIDGETS_PAUSED;
  3944. }
  3945. #endif
  3946. if (is_paused)
  3947. {
  3948. #if defined(HAVE_GFX_WIDGETS)
  3949. if (!widgets_active)
  3950. #endif
  3951. runloop_msg_queue_push(msg_hash_to_str(MSG_PAUSED), 1,
  3952. 1, true,
  3953. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  3954. if (!is_idle)
  3955. video_driver_cached_frame();
  3956. #ifdef HAVE_PRESENCE
  3957. userdata.status = PRESENCE_GAME_PAUSED;
  3958. command_event(CMD_EVENT_PRESENCE_UPDATE, &userdata);
  3959. #endif
  3960. #ifndef HAVE_LAKKA_SWITCH
  3961. #ifdef HAVE_LAKKA
  3962. set_cpu_scaling_signal(CPUSCALING_EVENT_FOCUS_MENU);
  3963. #endif
  3964. #endif /* #ifndef HAVE_LAKKA_SWITCH */
  3965. }
  3966. else
  3967. {
  3968. #ifndef HAVE_LAKKA_SWITCH
  3969. #ifdef HAVE_LAKKA
  3970. set_cpu_scaling_signal(CPUSCALING_EVENT_FOCUS_CORE);
  3971. #endif
  3972. #endif /* #ifndef HAVE_LAKKA_SWITCH */
  3973. }
  3974. #if defined(HAVE_TRANSLATE) && defined(HAVE_GFX_WIDGETS)
  3975. if (p_dispwidget->ai_service_overlay_state == 1)
  3976. gfx_widgets_ai_service_overlay_unload();
  3977. #endif
  3978. /* Signal/reset paused rewind to take the initial step */
  3979. runloop_st->run_frames_and_pause = -1;
  3980. }
  3981. struct string_list *path_get_subsystem_list(void)
  3982. {
  3983. runloop_state_t *runloop_st = &runloop_state;
  3984. return runloop_st->subsystem_fullpaths;
  3985. }
  3986. void runloop_path_fill_names(void)
  3987. {
  3988. runloop_state_t *runloop_st = &runloop_state;
  3989. #ifdef HAVE_BSV_MOVIE
  3990. input_driver_state_t *input_st = input_state_get_ptr();
  3991. #endif
  3992. runloop_path_init_savefile_internal(runloop_st);
  3993. #ifdef HAVE_BSV_MOVIE
  3994. strlcpy(input_st->bsv_movie_state.movie_auto_path,
  3995. runloop_st->name.replay,
  3996. sizeof(input_st->bsv_movie_state.movie_auto_path));
  3997. #endif
  3998. if (string_is_empty(runloop_st->runtime_content_path_basename))
  3999. return;
  4000. if (string_is_empty(runloop_st->name.ups))
  4001. {
  4002. size_t len = strlcpy(runloop_st->name.ups,
  4003. runloop_st->runtime_content_path_basename,
  4004. sizeof(runloop_st->name.ups));
  4005. runloop_st->name.ups[len ] = '.';
  4006. runloop_st->name.ups[len+1] = 'u';
  4007. runloop_st->name.ups[len+2] = 'p';
  4008. runloop_st->name.ups[len+3] = 's';
  4009. runloop_st->name.ups[len+4] = '\0';
  4010. }
  4011. if (string_is_empty(runloop_st->name.bps))
  4012. {
  4013. size_t len = strlcpy(runloop_st->name.bps,
  4014. runloop_st->runtime_content_path_basename,
  4015. sizeof(runloop_st->name.bps));
  4016. runloop_st->name.bps[len ] = '.';
  4017. runloop_st->name.bps[len+1] = 'b';
  4018. runloop_st->name.bps[len+2] = 'p';
  4019. runloop_st->name.bps[len+3] = 's';
  4020. runloop_st->name.bps[len+4] = '\0';
  4021. }
  4022. if (string_is_empty(runloop_st->name.ips))
  4023. {
  4024. size_t len = strlcpy(runloop_st->name.ips,
  4025. runloop_st->runtime_content_path_basename,
  4026. sizeof(runloop_st->name.ips));
  4027. runloop_st->name.ips[len ] = '.';
  4028. runloop_st->name.ips[len+1] = 'i';
  4029. runloop_st->name.ips[len+2] = 'p';
  4030. runloop_st->name.ips[len+3] = 's';
  4031. runloop_st->name.ips[len+4] = '\0';
  4032. }
  4033. }
  4034. /* Creates folder and core options stub file for subsequent runs */
  4035. bool core_options_create_override(bool game_specific)
  4036. {
  4037. char options_path[PATH_MAX_LENGTH];
  4038. runloop_state_t *runloop_st = &runloop_state;
  4039. config_file_t *conf = NULL;
  4040. options_path[0] = '\0';
  4041. if (game_specific)
  4042. {
  4043. /* Get options file path (game-specific) */
  4044. if (!validate_game_options(
  4045. runloop_st->system.info.library_name,
  4046. options_path,
  4047. sizeof(options_path), true))
  4048. goto error;
  4049. }
  4050. else
  4051. {
  4052. /* Sanity check - cannot create a folder-specific
  4053. * override if a game-specific override is
  4054. * already active */
  4055. if (runloop_st->flags & RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE)
  4056. goto error;
  4057. /* Get options file path (folder-specific) */
  4058. if (!validate_folder_options(
  4059. options_path,
  4060. sizeof(options_path), true))
  4061. goto error;
  4062. }
  4063. /* Open config file */
  4064. if (!(conf = config_file_new_from_path_to_string(options_path)))
  4065. if (!(conf = config_file_new_alloc()))
  4066. goto error;
  4067. /* Write config file */
  4068. core_option_manager_flush(runloop_st->core_options, conf);
  4069. if (!config_file_write(conf, options_path, true))
  4070. goto error;
  4071. runloop_msg_queue_push(
  4072. msg_hash_to_str(MSG_CORE_OPTIONS_FILE_CREATED_SUCCESSFULLY),
  4073. 1, 100, true,
  4074. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  4075. path_set(RARCH_PATH_CORE_OPTIONS, options_path);
  4076. if (game_specific)
  4077. runloop_st->flags |= RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE;
  4078. else
  4079. runloop_st->flags &= ~RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE;
  4080. if (!game_specific)
  4081. runloop_st->flags |= RUNLOOP_FLAG_FOLDER_OPTIONS_ACTIVE;
  4082. else
  4083. runloop_st->flags &= ~RUNLOOP_FLAG_FOLDER_OPTIONS_ACTIVE;
  4084. config_file_free(conf);
  4085. return true;
  4086. error:
  4087. runloop_msg_queue_push(
  4088. msg_hash_to_str(MSG_ERROR_SAVING_CORE_OPTIONS_FILE),
  4089. 1, 100, true,
  4090. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  4091. if (conf)
  4092. config_file_free(conf);
  4093. return false;
  4094. }
  4095. bool core_options_remove_override(bool game_specific)
  4096. {
  4097. char new_options_path[PATH_MAX_LENGTH];
  4098. runloop_state_t *runloop_st = &runloop_state;
  4099. settings_t *settings = config_get_ptr();
  4100. core_option_manager_t *coreopts = runloop_st->core_options;
  4101. bool per_core_options = !settings->bools.global_core_options;
  4102. const char *path_core_options = settings->paths.path_core_options;
  4103. const char *current_options_path = NULL;
  4104. config_file_t *conf = NULL;
  4105. bool folder_options_active = false;
  4106. new_options_path[0] = '\0';
  4107. /* Sanity check 1 - if there are no core options
  4108. * or no overrides are active, there is nothing to do */
  4109. if ( !coreopts ||
  4110. ( (!(runloop_st->flags & RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE))
  4111. && (!(runloop_st->flags & RUNLOOP_FLAG_FOLDER_OPTIONS_ACTIVE))
  4112. ))
  4113. return true;
  4114. /* Sanity check 2 - can only remove an override
  4115. * if the specified type is currently active */
  4116. if ( game_specific
  4117. && !(runloop_st->flags & RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE)
  4118. )
  4119. goto error;
  4120. /* Get current options file path */
  4121. current_options_path = path_get(RARCH_PATH_CORE_OPTIONS);
  4122. if (string_is_empty(current_options_path))
  4123. goto error;
  4124. /* Remove current options file, if required */
  4125. if (path_is_valid(current_options_path))
  4126. filestream_delete(current_options_path);
  4127. /* Reload any existing 'parent' options file
  4128. * > If we have removed a game-specific config,
  4129. * check whether a folder-specific config
  4130. * exists */
  4131. if (game_specific &&
  4132. validate_folder_options(
  4133. new_options_path,
  4134. sizeof(new_options_path), false) &&
  4135. path_is_valid(new_options_path))
  4136. folder_options_active = true;
  4137. /* > If a folder-specific config does not exist,
  4138. * or we removed it, check whether we have a
  4139. * top-level config file */
  4140. if (!folder_options_active)
  4141. {
  4142. /* Try core-specific options, if enabled */
  4143. if (per_core_options)
  4144. {
  4145. const char *core_name = runloop_st->system.info.library_name;
  4146. per_core_options = validate_per_core_options(
  4147. new_options_path, sizeof(new_options_path), true,
  4148. core_name, core_name);
  4149. }
  4150. /* ...otherwise use global options */
  4151. if (!per_core_options)
  4152. {
  4153. if (!string_is_empty(path_core_options))
  4154. strlcpy(new_options_path,
  4155. path_core_options, sizeof(new_options_path));
  4156. else if (!path_is_empty(RARCH_PATH_CONFIG))
  4157. fill_pathname_resolve_relative(
  4158. new_options_path, path_get(RARCH_PATH_CONFIG),
  4159. FILE_PATH_CORE_OPTIONS_CONFIG, sizeof(new_options_path));
  4160. }
  4161. }
  4162. if (string_is_empty(new_options_path))
  4163. goto error;
  4164. /* > If we have a valid file, load it */
  4165. if (folder_options_active ||
  4166. path_is_valid(new_options_path))
  4167. {
  4168. size_t i, j;
  4169. if (!(conf = config_file_new_from_path_to_string(new_options_path)))
  4170. goto error;
  4171. for (i = 0; i < coreopts->size; i++)
  4172. {
  4173. struct config_entry_list *entry = NULL;
  4174. struct core_option *option = (struct core_option*)&coreopts->opts[i];
  4175. if (!option)
  4176. continue;
  4177. if (!(entry = config_get_entry(conf, option->key)))
  4178. continue;
  4179. if (string_is_empty(entry->value))
  4180. continue;
  4181. /* Set current config value from file entry */
  4182. for (j = 0; j < option->vals->size; j++)
  4183. {
  4184. if (string_is_equal(option->vals->elems[j].data, entry->value))
  4185. {
  4186. option->index = j;
  4187. break;
  4188. }
  4189. }
  4190. }
  4191. coreopts->updated = true;
  4192. #ifdef HAVE_CHEEVOS
  4193. rcheevos_validate_config_settings();
  4194. #endif
  4195. }
  4196. /* Update runloop status */
  4197. if (folder_options_active)
  4198. {
  4199. path_set(RARCH_PATH_CORE_OPTIONS, new_options_path);
  4200. runloop_st->flags &= ~RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE;
  4201. runloop_st->flags |= RUNLOOP_FLAG_FOLDER_OPTIONS_ACTIVE;
  4202. }
  4203. else
  4204. {
  4205. path_clear(RARCH_PATH_CORE_OPTIONS);
  4206. runloop_st->flags &= ~(RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE
  4207. | RUNLOOP_FLAG_FOLDER_OPTIONS_ACTIVE);
  4208. /* Update config file path/object stored in
  4209. * core option manager struct */
  4210. strlcpy(coreopts->conf_path, new_options_path,
  4211. sizeof(coreopts->conf_path));
  4212. if (conf)
  4213. {
  4214. config_file_free(coreopts->conf);
  4215. coreopts->conf = conf;
  4216. conf = NULL;
  4217. }
  4218. }
  4219. runloop_msg_queue_push(
  4220. msg_hash_to_str(MSG_CORE_OPTIONS_FILE_REMOVED_SUCCESSFULLY),
  4221. 1, 100, true,
  4222. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  4223. if (conf)
  4224. config_file_free(conf);
  4225. return true;
  4226. error:
  4227. runloop_msg_queue_push(
  4228. msg_hash_to_str(MSG_ERROR_REMOVING_CORE_OPTIONS_FILE),
  4229. 1, 100, true,
  4230. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  4231. if (conf)
  4232. config_file_free(conf);
  4233. return false;
  4234. }
  4235. void core_options_reset(void)
  4236. {
  4237. size_t i;
  4238. runloop_state_t *runloop_st = &runloop_state;
  4239. core_option_manager_t *coreopts = runloop_st->core_options;
  4240. /* If there are no core options, there
  4241. * is nothing to do */
  4242. if (!coreopts || (coreopts->size < 1))
  4243. return;
  4244. for (i = 0; i < coreopts->size; i++)
  4245. coreopts->opts[i].index = coreopts->opts[i].default_index;
  4246. coreopts->updated = true;
  4247. #ifdef HAVE_CHEEVOS
  4248. rcheevos_validate_config_settings();
  4249. #endif
  4250. runloop_msg_queue_push(
  4251. msg_hash_to_str(MSG_CORE_OPTIONS_RESET),
  4252. 1, 100, true,
  4253. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  4254. }
  4255. void core_options_flush(void)
  4256. {
  4257. size_t _len;
  4258. runloop_state_t *runloop_st = &runloop_state;
  4259. core_option_manager_t *coreopts = runloop_st->core_options;
  4260. const char *path_core_options = path_get(RARCH_PATH_CORE_OPTIONS);
  4261. const char *core_options_file = NULL;
  4262. bool success = false;
  4263. char msg[256];
  4264. msg[0] = '\0';
  4265. /* If there are no core options, there
  4266. * is nothing to do */
  4267. if (!coreopts || (coreopts->size < 1))
  4268. return;
  4269. /* Check whether game/folder-specific options file
  4270. * is being used */
  4271. if (!string_is_empty(path_core_options))
  4272. {
  4273. config_file_t *conf_tmp = NULL;
  4274. bool path_valid = path_is_valid(path_core_options);
  4275. /* Attempt to load existing file */
  4276. if (path_valid)
  4277. conf_tmp = config_file_new_from_path_to_string(path_core_options);
  4278. /* Create new file if required */
  4279. if (!conf_tmp)
  4280. conf_tmp = config_file_new_alloc();
  4281. if (conf_tmp)
  4282. {
  4283. core_option_manager_flush(runloop_st->core_options, conf_tmp);
  4284. success = config_file_write(conf_tmp, path_core_options, true);
  4285. config_file_free(conf_tmp);
  4286. }
  4287. }
  4288. else
  4289. {
  4290. /* We are using the 'default' core options file */
  4291. path_core_options = runloop_st->core_options->conf_path;
  4292. if (!string_is_empty(path_core_options))
  4293. {
  4294. core_option_manager_flush(
  4295. runloop_st->core_options,
  4296. runloop_st->core_options->conf);
  4297. /* We must *guarantee* that a file gets written
  4298. * to disk if any options differ from the current
  4299. * options file contents. Must therefore handle
  4300. * the case where the 'default' file does not
  4301. * exist (e.g. if it gets deleted manually while
  4302. * a core is running) */
  4303. if (!path_is_valid(path_core_options))
  4304. runloop_st->core_options->conf->modified = true;
  4305. success = config_file_write(runloop_st->core_options->conf,
  4306. path_core_options, true);
  4307. }
  4308. }
  4309. /* Get options file name for display purposes */
  4310. if (!string_is_empty(path_core_options))
  4311. core_options_file = path_basename_nocompression(path_core_options);
  4312. if (string_is_empty(core_options_file))
  4313. core_options_file = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UNKNOWN);
  4314. if (success)
  4315. {
  4316. /* Log result */
  4317. _len = strlcpy(msg, msg_hash_to_str(MSG_CORE_OPTIONS_FLUSHED),
  4318. sizeof(msg));
  4319. RARCH_LOG(
  4320. "[Core]: Saved core options to \"%s\".\n",
  4321. path_core_options ? path_core_options : "UNKNOWN");
  4322. }
  4323. else
  4324. {
  4325. /* Log result */
  4326. _len = strlcpy(msg, msg_hash_to_str(MSG_CORE_OPTIONS_FLUSH_FAILED),
  4327. sizeof(msg));
  4328. RARCH_LOG(
  4329. "[Core]: Failed to save core options to \"%s\".\n",
  4330. path_core_options ? path_core_options : "UNKNOWN");
  4331. }
  4332. snprintf(msg + _len, sizeof(msg) - _len, " \"%s\"",
  4333. core_options_file);
  4334. runloop_msg_queue_push(
  4335. msg, 1, 100, true,
  4336. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  4337. }
  4338. void runloop_msg_queue_push(const char *msg,
  4339. unsigned prio, unsigned duration,
  4340. bool flush,
  4341. char *title,
  4342. enum message_queue_icon icon,
  4343. enum message_queue_category category)
  4344. {
  4345. #if defined(HAVE_GFX_WIDGETS)
  4346. dispgfx_widget_t *p_dispwidget = dispwidget_get_ptr();
  4347. bool widgets_active = p_dispwidget->active;
  4348. #endif
  4349. #ifdef HAVE_ACCESSIBILITY
  4350. settings_t *settings = config_get_ptr();
  4351. bool accessibility_enable = settings->bools.accessibility_enable;
  4352. unsigned accessibility_narrator_speech_speed = settings->uints.accessibility_narrator_speech_speed;
  4353. access_state_t *access_st = access_state_get_ptr();
  4354. #endif
  4355. runloop_state_t *runloop_st = &runloop_state;
  4356. RUNLOOP_MSG_QUEUE_LOCK(runloop_st);
  4357. #ifdef HAVE_ACCESSIBILITY
  4358. if (is_accessibility_enabled(
  4359. accessibility_enable,
  4360. access_st->enabled))
  4361. accessibility_speak_priority(
  4362. accessibility_enable,
  4363. accessibility_narrator_speech_speed,
  4364. (char*) msg, 0);
  4365. #endif
  4366. #if defined(HAVE_GFX_WIDGETS)
  4367. if (widgets_active)
  4368. {
  4369. gfx_widgets_msg_queue_push(
  4370. NULL,
  4371. msg,
  4372. roundf((float)duration / 60.0f * 1000.0f),
  4373. title,
  4374. icon,
  4375. category,
  4376. prio,
  4377. flush,
  4378. #ifdef HAVE_MENU
  4379. menu_state_get_ptr()->flags & MENU_ST_FLAG_ALIVE
  4380. #else
  4381. false
  4382. #endif
  4383. );
  4384. duration = duration * 60 / 1000;
  4385. }
  4386. else
  4387. #endif
  4388. {
  4389. if (flush)
  4390. msg_queue_clear(&runloop_st->msg_queue);
  4391. msg_queue_push(&runloop_st->msg_queue, msg,
  4392. prio, duration,
  4393. title, icon, category);
  4394. runloop_st->msg_queue_size = msg_queue_size(
  4395. &runloop_st->msg_queue);
  4396. }
  4397. ui_companion_driver_msg_queue_push(
  4398. msg, prio, duration, flush);
  4399. RUNLOOP_MSG_QUEUE_UNLOCK(runloop_st);
  4400. }
  4401. #ifdef HAVE_MENU
  4402. /* Display the libretro core's framebuffer onscreen. */
  4403. static bool display_menu_libretro(
  4404. runloop_state_t *runloop_st,
  4405. input_driver_state_t *input_st,
  4406. float slowmotion_ratio,
  4407. bool libretro_running,
  4408. retro_time_t current_time)
  4409. {
  4410. bool runloop_idle = runloop_st->flags & RUNLOOP_FLAG_IDLE;
  4411. video_driver_state_t*video_st = video_state_get_ptr();
  4412. if ( video_st->poke
  4413. && video_st->poke->set_texture_enable)
  4414. video_st->poke->set_texture_enable(video_st->data, true, false);
  4415. if (libretro_running)
  4416. {
  4417. if (!(input_st->flags & INP_FLAG_BLOCK_LIBRETRO_INPUT))
  4418. input_st->flags |= INP_FLAG_BLOCK_LIBRETRO_INPUT;
  4419. core_run();
  4420. runloop_st->core_runtime_usec +=
  4421. runloop_core_runtime_tick(runloop_st, slowmotion_ratio, current_time);
  4422. input_st->flags &= ~INP_FLAG_BLOCK_LIBRETRO_INPUT;
  4423. return false;
  4424. }
  4425. if (runloop_idle)
  4426. {
  4427. #ifdef HAVE_PRESENCE
  4428. presence_userdata_t userdata;
  4429. userdata.status = PRESENCE_GAME_PAUSED;
  4430. command_event(CMD_EVENT_PRESENCE_UPDATE, &userdata);
  4431. #endif
  4432. return false;
  4433. }
  4434. return true;
  4435. }
  4436. #endif
  4437. #define HOTKEY_CHECK(cmd1, cmd2, cond, cond2) \
  4438. { \
  4439. static bool old_pressed = false; \
  4440. bool pressed = BIT256_GET(current_bits, cmd1); \
  4441. if (pressed && !old_pressed) \
  4442. if (cond) \
  4443. command_event(cmd2, cond2); \
  4444. old_pressed = pressed; \
  4445. }
  4446. #define HOTKEY_CHECK3(cmd1, cmd2, cmd3, cmd4, cmd5, cmd6) \
  4447. { \
  4448. static bool old_pressed = false; \
  4449. static bool old_pressed2 = false; \
  4450. static bool old_pressed3 = false; \
  4451. bool pressed = BIT256_GET(current_bits, cmd1); \
  4452. bool pressed2 = BIT256_GET(current_bits, cmd3); \
  4453. bool pressed3 = BIT256_GET(current_bits, cmd5); \
  4454. if (pressed && !old_pressed) \
  4455. command_event(cmd2, (void*)(intptr_t)0); \
  4456. else if (pressed2 && !old_pressed2) \
  4457. command_event(cmd4, (void*)(intptr_t)0); \
  4458. else if (pressed3 && !old_pressed3) \
  4459. command_event(cmd6, (void*)(intptr_t)0); \
  4460. old_pressed = pressed; \
  4461. old_pressed2 = pressed2; \
  4462. old_pressed3 = pressed3; \
  4463. }
  4464. static void runloop_pause_toggle(
  4465. bool *runloop_paused_hotkey,
  4466. bool pause_pressed, bool old_pause_pressed,
  4467. bool focused, bool old_focus)
  4468. {
  4469. runloop_state_t *runloop_st = &runloop_state;
  4470. if (focused)
  4471. {
  4472. if (pause_pressed && !old_pause_pressed)
  4473. {
  4474. /* Keep track of hotkey triggered pause to
  4475. * distinguish it from menu triggered pause */
  4476. *runloop_paused_hotkey = !(runloop_st->flags & RUNLOOP_FLAG_PAUSED);
  4477. command_event(CMD_EVENT_PAUSE_TOGGLE, NULL);
  4478. }
  4479. else if (!old_focus)
  4480. command_event(CMD_EVENT_UNPAUSE, NULL);
  4481. }
  4482. else if (old_focus)
  4483. command_event(CMD_EVENT_PAUSE, NULL);
  4484. }
  4485. static enum runloop_state_enum runloop_check_state(
  4486. bool error_on_init,
  4487. settings_t *settings,
  4488. retro_time_t current_time)
  4489. {
  4490. input_bits_t current_bits;
  4491. #ifdef HAVE_MENU
  4492. static input_bits_t last_input = {{0}};
  4493. #endif
  4494. uico_driver_state_t *uico_st = uico_state_get_ptr();
  4495. input_driver_state_t *input_st = input_state_get_ptr();
  4496. video_driver_state_t *video_st = video_state_get_ptr();
  4497. gfx_display_t *p_disp = disp_get_ptr();
  4498. runloop_state_t *runloop_st = &runloop_state;
  4499. static bool old_focus = true;
  4500. static bool runloop_paused_hotkey = false;
  4501. struct retro_callbacks *cbs = &runloop_st->retro_ctx;
  4502. bool is_focused = false;
  4503. bool is_alive = false;
  4504. uint64_t frame_count = 0;
  4505. bool focused = true;
  4506. bool rarch_is_initialized = runloop_st->flags & RUNLOOP_FLAG_IS_INITED;
  4507. bool runloop_paused = runloop_st->flags & RUNLOOP_FLAG_PAUSED;
  4508. bool pause_nonactive = settings->bools.pause_nonactive;
  4509. unsigned quit_gamepad_combo = settings->uints.input_quit_gamepad_combo;
  4510. #ifdef HAVE_MENU
  4511. struct menu_state *menu_st = menu_state_get_ptr();
  4512. menu_handle_t *menu = menu_st->driver_data;
  4513. unsigned menu_toggle_gamepad_combo = settings->uints.input_menu_toggle_gamepad_combo;
  4514. bool menu_driver_binding_state = menu_st->flags & MENU_ST_FLAG_IS_BINDING;
  4515. bool menu_is_alive = menu_st->flags & MENU_ST_FLAG_ALIVE;
  4516. bool display_kb = menu_input_dialog_get_display_kb();
  4517. #endif
  4518. #if defined(HAVE_GFX_WIDGETS)
  4519. dispgfx_widget_t *p_dispwidget = dispwidget_get_ptr();
  4520. bool widgets_active = p_dispwidget->active;
  4521. #endif
  4522. #ifdef HAVE_CHEEVOS
  4523. bool cheevos_hardcore_active = false;
  4524. #endif
  4525. #ifdef ANDROID
  4526. struct android_app *app = (struct android_app*)g_android;
  4527. #endif
  4528. #if defined(HAVE_TRANSLATE) && defined(HAVE_GFX_WIDGETS)
  4529. if (p_dispwidget->ai_service_overlay_state == 3)
  4530. {
  4531. command_event(CMD_EVENT_PAUSE, NULL);
  4532. p_dispwidget->ai_service_overlay_state = 1;
  4533. }
  4534. #endif
  4535. #ifdef HAVE_LIBNX
  4536. /* Should be called once per frame */
  4537. if (!appletMainLoop())
  4538. return RUNLOOP_STATE_QUIT;
  4539. #endif
  4540. #ifdef _3DS
  4541. /* Should be called once per frame */
  4542. if (!aptMainLoop())
  4543. return RUNLOOP_STATE_QUIT;
  4544. #endif
  4545. BIT256_CLEAR_ALL_PTR(&current_bits);
  4546. input_st->flags &= ~(INP_FLAG_BLOCK_LIBRETRO_INPUT
  4547. | INP_FLAG_BLOCK_HOTKEY);
  4548. if (input_st->flags & INP_FLAG_KB_MAPPING_BLOCKED)
  4549. input_st->flags |= INP_FLAG_BLOCK_HOTKEY;
  4550. input_driver_collect_system_input(input_st, settings, &current_bits);
  4551. #ifdef HAVE_MENU
  4552. last_input = current_bits;
  4553. if (
  4554. ((menu_toggle_gamepad_combo != INPUT_COMBO_NONE) &&
  4555. input_driver_button_combo(
  4556. menu_toggle_gamepad_combo,
  4557. current_time,
  4558. &last_input)))
  4559. BIT256_SET(current_bits, RARCH_MENU_TOGGLE);
  4560. if (menu_st->input_driver_flushing_input > 0)
  4561. {
  4562. bool input_active = bits_any_set(current_bits.data, ARRAY_SIZE(current_bits.data));
  4563. /* Don't count 'enable_hotkey' as active input */
  4564. if ( input_active
  4565. && BIT256_GET(current_bits, RARCH_ENABLE_HOTKEY)
  4566. && !BIT256_GET(current_bits, RARCH_MENU_TOGGLE))
  4567. input_active = false;
  4568. if (!input_active)
  4569. menu_st->input_driver_flushing_input--;
  4570. if (input_active || (menu_st->input_driver_flushing_input > 0))
  4571. {
  4572. BIT256_CLEAR_ALL(current_bits);
  4573. if (runloop_paused && !runloop_paused_hotkey && settings->bools.menu_pause_libretro)
  4574. BIT256_SET(current_bits, RARCH_PAUSE_TOGGLE);
  4575. else if (runloop_paused_hotkey)
  4576. {
  4577. /* Restore pause if pause is triggered with both hotkey and menu,
  4578. * and restore cached video frame to continue properly to
  4579. * paused state from non-paused menu */
  4580. if (settings->bools.menu_pause_libretro)
  4581. command_event(CMD_EVENT_PAUSE, NULL);
  4582. else
  4583. video_driver_cached_frame();
  4584. }
  4585. }
  4586. }
  4587. #endif
  4588. if (!VIDEO_DRIVER_IS_THREADED_INTERNAL(video_st))
  4589. {
  4590. const ui_application_t *application = uico_st->drv
  4591. ? uico_st->drv->application
  4592. : NULL;
  4593. if (application)
  4594. application->process_events();
  4595. }
  4596. frame_count = video_st->frame_count;
  4597. is_alive = video_st->current_video
  4598. ? video_st->current_video->alive(video_st->data)
  4599. : true;
  4600. is_focused = VIDEO_HAS_FOCUS(video_st);
  4601. #ifdef HAVE_MENU
  4602. if (menu_driver_binding_state)
  4603. BIT256_CLEAR_ALL(current_bits);
  4604. #endif
  4605. /* Check fullscreen hotkey */
  4606. HOTKEY_CHECK(RARCH_FULLSCREEN_TOGGLE_KEY, CMD_EVENT_FULLSCREEN_TOGGLE, true, NULL);
  4607. /* Check mouse grab hotkey */
  4608. HOTKEY_CHECK(RARCH_GRAB_MOUSE_TOGGLE, CMD_EVENT_GRAB_MOUSE_TOGGLE, true, NULL);
  4609. /* Automatic mouse grab on focus */
  4610. if ( settings->bools.input_auto_mouse_grab
  4611. && (is_focused)
  4612. && (is_focused != (((runloop_st->flags & RUNLOOP_FLAG_FOCUSED)) > 0))
  4613. && !(input_st->flags & INP_FLAG_GRAB_MOUSE_STATE))
  4614. command_event(CMD_EVENT_GRAB_MOUSE_TOGGLE, NULL);
  4615. if (is_focused)
  4616. runloop_st->flags |= RUNLOOP_FLAG_FOCUSED;
  4617. else
  4618. runloop_st->flags &= ~RUNLOOP_FLAG_FOCUSED;
  4619. #ifdef HAVE_OVERLAY
  4620. if (settings->bools.input_overlay_enable)
  4621. {
  4622. static char prev_overlay_restore = false;
  4623. static unsigned last_width = 0;
  4624. static unsigned last_height = 0;
  4625. unsigned video_driver_width = video_st->width;
  4626. unsigned video_driver_height = video_st->height;
  4627. bool check_next_rotation = true;
  4628. bool input_overlay_hide_when_gamepad_connected = settings->bools.input_overlay_hide_when_gamepad_connected;
  4629. bool input_overlay_auto_rotate = settings->bools.input_overlay_auto_rotate;
  4630. /* Check whether overlay should be hidden
  4631. * when a gamepad is connected */
  4632. if (input_overlay_hide_when_gamepad_connected)
  4633. {
  4634. static bool last_controller_connected = false;
  4635. bool controller_connected = (input_config_get_device_name(0) != NULL);
  4636. if (controller_connected != last_controller_connected)
  4637. {
  4638. if (controller_connected)
  4639. input_overlay_deinit();
  4640. else
  4641. input_overlay_init();
  4642. last_controller_connected = controller_connected;
  4643. }
  4644. }
  4645. /* Check next overlay hotkey */
  4646. HOTKEY_CHECK(RARCH_OVERLAY_NEXT, CMD_EVENT_OVERLAY_NEXT, true, &check_next_rotation);
  4647. /* Ensure overlay is restored after displaying OSK */
  4648. if (input_st->flags & INP_FLAG_KB_LINEFEED_ENABLE)
  4649. prev_overlay_restore = true;
  4650. else if (prev_overlay_restore)
  4651. {
  4652. input_overlay_init();
  4653. prev_overlay_restore = false;
  4654. }
  4655. /* Check whether video aspect has changed */
  4656. if ((video_driver_width != last_width) ||
  4657. (video_driver_height != last_height))
  4658. {
  4659. /* Update scaling/offset factors */
  4660. command_event(CMD_EVENT_OVERLAY_SET_SCALE_FACTOR, NULL);
  4661. /* Check overlay rotation, if required */
  4662. if (input_overlay_auto_rotate)
  4663. input_overlay_auto_rotate_(
  4664. video_st->width,
  4665. video_st->height,
  4666. settings->bools.input_overlay_enable,
  4667. input_st->overlay_ptr);
  4668. last_width = video_driver_width;
  4669. last_height = video_driver_height;
  4670. }
  4671. /* Check OSK hotkey */
  4672. HOTKEY_CHECK(RARCH_OSK, CMD_EVENT_OSK_TOGGLE, true, NULL);
  4673. }
  4674. #endif
  4675. /*
  4676. * If the Aspect Ratio is FULL then update the aspect ratio to the
  4677. * current video driver aspect ratio (The full window)
  4678. *
  4679. * TODO/FIXME
  4680. * Should possibly be refactored to have last width & driver width & height
  4681. * only be done once when we are using an overlay OR using aspect ratio
  4682. * full
  4683. */
  4684. if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_FULL)
  4685. {
  4686. static unsigned last_width = 0;
  4687. static unsigned last_height = 0;
  4688. unsigned video_driver_width = video_st->width;
  4689. unsigned video_driver_height = video_st->height;
  4690. /* Check whether video aspect has changed */
  4691. if ((video_driver_width != last_width) ||
  4692. (video_driver_height != last_height))
  4693. {
  4694. /* Update set aspect ratio so the full matches the current video width & height */
  4695. command_event(CMD_EVENT_VIDEO_SET_ASPECT_RATIO, NULL);
  4696. last_width = video_driver_width;
  4697. last_height = video_driver_height;
  4698. }
  4699. }
  4700. #ifdef ANDROID
  4701. /* transfer select + start button */
  4702. if (BIT256_GET(current_bits, RARCH_JOYPAD_SELECT)
  4703. && BIT256_GET(current_bits, RARCH_JOYPAD_START)
  4704. && app->openGameDialogRequested == 0) {
  4705. android_app_write_cmd(app, APP_CMD_GAME_DIALOG_OPENED);
  4706. }
  4707. #endif
  4708. /* Check quit hotkey */
  4709. {
  4710. bool trig_quit_key, quit_press_twice;
  4711. static bool quit_key = false;
  4712. static bool old_quit_key = false;
  4713. static bool runloop_exec = false;
  4714. quit_key = BIT256_GET(
  4715. current_bits, RARCH_QUIT_KEY);
  4716. trig_quit_key = quit_key && !old_quit_key;
  4717. /* Check for quit gamepad combo */
  4718. if (!trig_quit_key &&
  4719. ((quit_gamepad_combo != INPUT_COMBO_NONE) &&
  4720. input_driver_button_combo(
  4721. quit_gamepad_combo,
  4722. current_time,
  4723. &current_bits)))
  4724. trig_quit_key = true;
  4725. old_quit_key = quit_key;
  4726. quit_press_twice = settings->bools.quit_press_twice;
  4727. /* Check double press if enabled */
  4728. if (trig_quit_key && quit_press_twice)
  4729. {
  4730. static retro_time_t quit_key_time = 0;
  4731. retro_time_t cur_time = current_time;
  4732. trig_quit_key = (cur_time - quit_key_time < QUIT_DELAY_USEC);
  4733. quit_key_time = cur_time;
  4734. if (!trig_quit_key)
  4735. {
  4736. float target_hz = 0.0;
  4737. runloop_environment_cb(
  4738. RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE, &target_hz);
  4739. runloop_msg_queue_push(msg_hash_to_str(MSG_PRESS_AGAIN_TO_QUIT), 1,
  4740. QUIT_DELAY_USEC * target_hz / 1000000,
  4741. true, NULL,
  4742. MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  4743. }
  4744. }
  4745. if (RUNLOOP_TIME_TO_EXIT(trig_quit_key))
  4746. {
  4747. bool quit_runloop = false;
  4748. #ifdef HAVE_SCREENSHOTS
  4749. unsigned runloop_max_frames = runloop_st->max_frames;
  4750. if ((runloop_max_frames != 0)
  4751. && (frame_count >= runloop_max_frames)
  4752. && (runloop_st->flags & RUNLOOP_FLAG_MAX_FRAMES_SCREENSHOT))
  4753. {
  4754. const char *screenshot_path = NULL;
  4755. bool fullpath = false;
  4756. if (string_is_empty(runloop_st->max_frames_screenshot_path))
  4757. screenshot_path = path_get(RARCH_PATH_BASENAME);
  4758. else
  4759. {
  4760. fullpath = true;
  4761. screenshot_path = runloop_st->max_frames_screenshot_path;
  4762. }
  4763. RARCH_LOG("Taking a screenshot before exiting...\n");
  4764. /* Take a screenshot before we exit. */
  4765. if (!take_screenshot(settings->paths.directory_screenshot,
  4766. screenshot_path, false,
  4767. video_driver_cached_frame_has_valid_framebuffer(), fullpath, false))
  4768. {
  4769. RARCH_ERR("Could not take a screenshot before exiting.\n");
  4770. }
  4771. }
  4772. #endif
  4773. if (runloop_exec)
  4774. runloop_exec = false;
  4775. if (runloop_st->flags & RUNLOOP_FLAG_CORE_SHUTDOWN_INITIATED)
  4776. {
  4777. bool load_dummy_core = false;
  4778. runloop_st->flags &= ~RUNLOOP_FLAG_CORE_SHUTDOWN_INITIATED;
  4779. /* Check whether dummy core should be loaded
  4780. * instead of exiting RetroArch completely
  4781. * (aborts shutdown if invoked) */
  4782. if (settings->bools.load_dummy_on_core_shutdown)
  4783. {
  4784. load_dummy_core = true;
  4785. runloop_st->flags &= ~RUNLOOP_FLAG_SHUTDOWN_INITIATED;
  4786. }
  4787. /* Unload current core, and load dummy if
  4788. * required */
  4789. if (!command_event(CMD_EVENT_UNLOAD_CORE, &load_dummy_core))
  4790. {
  4791. runloop_st->flags |= RUNLOOP_FLAG_SHUTDOWN_INITIATED;
  4792. quit_runloop = true;
  4793. }
  4794. if (!load_dummy_core)
  4795. quit_runloop = true;
  4796. }
  4797. else
  4798. quit_runloop = true;
  4799. runloop_st->flags &= ~RUNLOOP_FLAG_CORE_RUNNING;
  4800. if (quit_runloop)
  4801. {
  4802. old_quit_key = quit_key;
  4803. return RUNLOOP_STATE_QUIT;
  4804. }
  4805. }
  4806. }
  4807. #if defined(HAVE_MENU) || defined(HAVE_GFX_WIDGETS)
  4808. gfx_animation_update(
  4809. current_time,
  4810. settings->bools.menu_timedate_enable,
  4811. settings->floats.menu_ticker_speed,
  4812. video_st->width,
  4813. video_st->height);
  4814. #if defined(HAVE_GFX_WIDGETS)
  4815. if (widgets_active)
  4816. {
  4817. bool rarch_force_fullscreen = video_st->flags &
  4818. VIDEO_FLAG_FORCE_FULLSCREEN;
  4819. bool video_is_fullscreen = settings->bools.video_fullscreen ||
  4820. rarch_force_fullscreen;
  4821. RUNLOOP_MSG_QUEUE_LOCK(runloop_st);
  4822. gfx_widgets_iterate(
  4823. p_disp,
  4824. settings,
  4825. video_st->width,
  4826. video_st->height,
  4827. video_is_fullscreen,
  4828. settings->paths.directory_assets,
  4829. settings->paths.path_font,
  4830. VIDEO_DRIVER_IS_THREADED_INTERNAL(video_st));
  4831. RUNLOOP_MSG_QUEUE_UNLOCK(runloop_st);
  4832. }
  4833. #endif
  4834. #ifdef HAVE_MENU
  4835. if (menu_is_alive)
  4836. {
  4837. enum menu_action action;
  4838. static input_bits_t old_input = {{0}};
  4839. static enum menu_action
  4840. old_action = MENU_ACTION_CANCEL;
  4841. struct menu_state *menu_st = menu_state_get_ptr();
  4842. bool focused = false;
  4843. input_bits_t trigger_input = current_bits;
  4844. unsigned screensaver_timeout = settings->uints.menu_screensaver_timeout;
  4845. /* Get current time */
  4846. menu_st->current_time_us = current_time;
  4847. cbs->poll_cb();
  4848. bits_clear_bits(trigger_input.data, old_input.data,
  4849. ARRAY_SIZE(trigger_input.data));
  4850. action = (enum menu_action)menu_event(
  4851. settings,
  4852. &current_bits, &trigger_input, display_kb);
  4853. #ifdef HAVE_NETWORKING
  4854. if (!netplay_driver_ctl(RARCH_NETPLAY_CTL_ALLOW_PAUSE, NULL))
  4855. focused = true;
  4856. else
  4857. #endif
  4858. {
  4859. if (pause_nonactive)
  4860. focused = is_focused && (!(uico_st->flags & UICO_ST_FLAG_IS_ON_FOREGROUND));
  4861. else
  4862. focused = (!(uico_st->flags & UICO_ST_FLAG_IS_ON_FOREGROUND));
  4863. }
  4864. if (action == old_action)
  4865. {
  4866. retro_time_t press_time = current_time;
  4867. if (action == MENU_ACTION_NOOP)
  4868. menu_st->noop_press_time = press_time - menu_st->noop_start_time;
  4869. else
  4870. menu_st->action_press_time = press_time - menu_st->action_start_time;
  4871. }
  4872. else
  4873. {
  4874. if (action == MENU_ACTION_NOOP)
  4875. {
  4876. menu_st->noop_start_time = current_time;
  4877. menu_st->noop_press_time = 0;
  4878. if (menu_st->prev_action == old_action)
  4879. menu_st->action_start_time = menu_st->prev_start_time;
  4880. else
  4881. menu_st->action_start_time = current_time;
  4882. }
  4883. else
  4884. {
  4885. if ( menu_st->prev_action == action
  4886. && menu_st->noop_press_time < 200000) /* 250ms */
  4887. {
  4888. menu_st->action_start_time = menu_st->prev_start_time;
  4889. menu_st->action_press_time = current_time - menu_st->action_start_time;
  4890. }
  4891. else
  4892. {
  4893. menu_st->prev_start_time = current_time;
  4894. menu_st->prev_action = action;
  4895. menu_st->action_press_time = 0;
  4896. }
  4897. }
  4898. }
  4899. /* Check whether menu screensaver should be enabled */
  4900. if ( (screensaver_timeout > 0)
  4901. && (menu_st->flags & MENU_ST_FLAG_SCREENSAVER_SUPPORTED)
  4902. && (!(menu_st->flags & MENU_ST_FLAG_SCREENSAVER_ACTIVE))
  4903. && ((menu_st->current_time_us - menu_st->input_last_time_us)
  4904. > ((retro_time_t)screensaver_timeout * 1000000)))
  4905. {
  4906. menu_st->flags |= MENU_ST_FLAG_SCREENSAVER_ACTIVE;
  4907. if (menu_st->driver_ctx->environ_cb)
  4908. menu_st->driver_ctx->environ_cb(MENU_ENVIRON_ENABLE_SCREENSAVER,
  4909. NULL, menu_st->userdata);
  4910. }
  4911. /* Iterate the menu driver for one frame. */
  4912. /* If the user had requested that the Quick Menu
  4913. * be spawned during the previous frame, do this now
  4914. * and exit the function to go to the next frame. */
  4915. if (menu_st->flags & MENU_ST_FLAG_PENDING_QUICK_MENU)
  4916. {
  4917. /* We are going to push a new menu; ensure
  4918. * that the current one is cached for animation
  4919. * purposes */
  4920. if (menu_st->driver_ctx && menu_st->driver_ctx->list_cache)
  4921. menu_st->driver_ctx->list_cache(menu_st->userdata,
  4922. MENU_LIST_PLAIN, MENU_ACTION_NOOP);
  4923. p_disp->flags |= GFX_DISP_FLAG_MSG_FORCE;
  4924. generic_action_ok_displaylist_push("", NULL,
  4925. "", 0, 0, 0, ACTION_OK_DL_CONTENT_SETTINGS);
  4926. menu_st->selection_ptr = 0;
  4927. menu_st->flags &= ~MENU_ST_FLAG_PENDING_QUICK_MENU;
  4928. }
  4929. else if (!menu_driver_iterate(
  4930. menu_st,
  4931. p_disp,
  4932. anim_get_ptr(),
  4933. settings,
  4934. action, current_time))
  4935. {
  4936. if (error_on_init)
  4937. {
  4938. content_ctx_info_t content_info = {0};
  4939. task_push_start_dummy_core(&content_info);
  4940. }
  4941. else
  4942. retroarch_menu_running_finished(false);
  4943. }
  4944. if (focused || !(runloop_st->flags & RUNLOOP_FLAG_IDLE))
  4945. {
  4946. bool runloop_is_inited = runloop_st->flags & RUNLOOP_FLAG_IS_INITED;
  4947. #ifdef HAVE_NETWORKING
  4948. bool menu_pause_libretro = settings->bools.menu_pause_libretro &&
  4949. netplay_driver_ctl(RARCH_NETPLAY_CTL_ALLOW_PAUSE, NULL);
  4950. #else
  4951. bool menu_pause_libretro = settings->bools.menu_pause_libretro;
  4952. #endif
  4953. bool libretro_running = !(runloop_st->flags & RUNLOOP_FLAG_PAUSED)
  4954. && !menu_pause_libretro
  4955. && runloop_is_inited
  4956. && (runloop_st->current_core_type != CORE_TYPE_DUMMY);
  4957. if (menu)
  4958. {
  4959. if (BIT64_GET(menu->state, MENU_STATE_RENDER_FRAMEBUFFER)
  4960. != BIT64_GET(menu->state, MENU_STATE_RENDER_MESSAGEBOX))
  4961. BIT64_SET(menu->state, MENU_STATE_RENDER_FRAMEBUFFER);
  4962. if (BIT64_GET(menu->state, MENU_STATE_RENDER_FRAMEBUFFER))
  4963. p_disp->flags |= GFX_DISP_FLAG_FB_DIRTY;
  4964. if (BIT64_GET(menu->state, MENU_STATE_RENDER_MESSAGEBOX)
  4965. && !string_is_empty(menu->menu_state_msg))
  4966. {
  4967. if (menu->driver_ctx->render_messagebox)
  4968. menu->driver_ctx->render_messagebox(
  4969. menu->userdata,
  4970. menu->menu_state_msg);
  4971. if (uico_st->flags & UICO_ST_FLAG_IS_ON_FOREGROUND)
  4972. {
  4973. if ( uico_st->drv
  4974. && uico_st->drv->render_messagebox)
  4975. uico_st->drv->render_messagebox(menu->menu_state_msg);
  4976. }
  4977. }
  4978. if (BIT64_GET(menu->state, MENU_STATE_BLIT))
  4979. {
  4980. if (menu->driver_ctx->render)
  4981. menu->driver_ctx->render(
  4982. menu->userdata,
  4983. video_st->width,
  4984. video_st->height,
  4985. runloop_st->flags & RUNLOOP_FLAG_IDLE);
  4986. }
  4987. if ( (menu_st->flags & MENU_ST_FLAG_ALIVE)
  4988. && !(runloop_st->flags & RUNLOOP_FLAG_IDLE))
  4989. if (display_menu_libretro(runloop_st, input_st,
  4990. settings->floats.slowmotion_ratio,
  4991. libretro_running, current_time))
  4992. video_driver_cached_frame();
  4993. if (menu->driver_ctx->set_texture)
  4994. menu->driver_ctx->set_texture(menu->userdata);
  4995. menu->state = 0;
  4996. }
  4997. if (settings->bools.audio_enable_menu &&
  4998. !libretro_running)
  4999. audio_driver_menu_sample();
  5000. }
  5001. old_input = current_bits;
  5002. old_action = action;
  5003. if (!focused || (runloop_st->flags & RUNLOOP_FLAG_IDLE))
  5004. return RUNLOOP_STATE_POLLED_AND_SLEEP;
  5005. }
  5006. else
  5007. #endif
  5008. #endif
  5009. {
  5010. if (runloop_st->flags & RUNLOOP_FLAG_IDLE)
  5011. {
  5012. cbs->poll_cb();
  5013. return RUNLOOP_STATE_POLLED_AND_SLEEP;
  5014. }
  5015. }
  5016. /* Check Game Focus hotkey */
  5017. {
  5018. enum input_game_focus_cmd_type game_focus_cmd = GAME_FOCUS_CMD_TOGGLE;
  5019. HOTKEY_CHECK(RARCH_GAME_FOCUS_TOGGLE, CMD_EVENT_GAME_FOCUS_TOGGLE, true, &game_focus_cmd);
  5020. }
  5021. /* Check UI companion hotkey */
  5022. HOTKEY_CHECK(RARCH_UI_COMPANION_TOGGLE, CMD_EVENT_UI_COMPANION_TOGGLE, true, NULL);
  5023. /* Check close content hotkey */
  5024. HOTKEY_CHECK(RARCH_CLOSE_CONTENT_KEY, CMD_EVENT_CLOSE_CONTENT, true, NULL);
  5025. #ifdef HAVE_MENU
  5026. /* Check menu hotkey */
  5027. {
  5028. static bool old_pressed = false;
  5029. char *menu_driver = settings->arrays.menu_driver;
  5030. bool pressed = BIT256_GET(current_bits, RARCH_MENU_TOGGLE)
  5031. && !string_is_equal(menu_driver, "null");
  5032. bool core_type_is_dummy = runloop_st->current_core_type == CORE_TYPE_DUMMY;
  5033. if ( (pressed && !old_pressed) ||
  5034. core_type_is_dummy)
  5035. {
  5036. if (menu_st->flags & MENU_ST_FLAG_ALIVE)
  5037. {
  5038. if (rarch_is_initialized && !core_type_is_dummy)
  5039. retroarch_menu_running_finished(false);
  5040. }
  5041. else
  5042. retroarch_menu_running();
  5043. }
  5044. old_pressed = pressed;
  5045. }
  5046. #endif
  5047. /* Check FPS hotkey */
  5048. HOTKEY_CHECK(RARCH_FPS_TOGGLE, CMD_EVENT_FPS_TOGGLE, true, NULL);
  5049. /* Check statistics hotkey */
  5050. HOTKEY_CHECK(RARCH_STATISTICS_TOGGLE, CMD_EVENT_STATISTICS_TOGGLE, true, NULL);
  5051. /* Check netplay host hotkey */
  5052. HOTKEY_CHECK(RARCH_NETPLAY_HOST_TOGGLE, CMD_EVENT_NETPLAY_HOST_TOGGLE, true, NULL);
  5053. /* Volume stepping + acceleration */
  5054. {
  5055. static unsigned volume_hotkey_delay = 0;
  5056. static unsigned volume_hotkey_delay_active = 0;
  5057. unsigned volume_hotkey_delay_default = 6;
  5058. bool volume_hotkey_up = BIT256_GET(
  5059. current_bits, RARCH_VOLUME_UP);
  5060. bool volume_hotkey_down = BIT256_GET(
  5061. current_bits, RARCH_VOLUME_DOWN);
  5062. if ( (volume_hotkey_up && !volume_hotkey_down) ||
  5063. (volume_hotkey_down && !volume_hotkey_up))
  5064. {
  5065. if (volume_hotkey_delay > 0)
  5066. volume_hotkey_delay--;
  5067. else
  5068. {
  5069. if (volume_hotkey_up)
  5070. command_event(CMD_EVENT_VOLUME_UP, NULL);
  5071. else if (volume_hotkey_down)
  5072. command_event(CMD_EVENT_VOLUME_DOWN, NULL);
  5073. if (volume_hotkey_delay_active > 0)
  5074. volume_hotkey_delay_active--;
  5075. volume_hotkey_delay = volume_hotkey_delay_active;
  5076. }
  5077. }
  5078. else
  5079. {
  5080. volume_hotkey_delay = 0;
  5081. volume_hotkey_delay_active = volume_hotkey_delay_default;
  5082. }
  5083. }
  5084. /* Check audio mute hotkey */
  5085. HOTKEY_CHECK(RARCH_MUTE, CMD_EVENT_AUDIO_MUTE_TOGGLE, true, NULL);
  5086. #ifdef HAVE_SCREENSHOTS
  5087. /* Check screenshot hotkey */
  5088. HOTKEY_CHECK(RARCH_SCREENSHOT, CMD_EVENT_TAKE_SCREENSHOT, true, NULL);
  5089. #endif
  5090. #ifdef HAVE_CHEEVOS
  5091. if (!cheevos_hardcore_active)
  5092. #endif
  5093. {
  5094. /* Check rewind hotkey */
  5095. /* > Must do this before MENU_ITERATE to not lose rewind steps
  5096. * while menu is active when menu pause is disabled */
  5097. {
  5098. #ifdef HAVE_REWIND
  5099. char s[128];
  5100. bool rewinding = false;
  5101. static bool old_rewind_pressed = false;
  5102. bool rewind_pressed = BIT256_GET(current_bits, RARCH_REWIND);
  5103. unsigned t = 0;
  5104. s[0] = '\0';
  5105. #ifdef HAVE_MENU
  5106. /* Don't allow rewinding while menu is active */
  5107. if (menu_st->flags & MENU_ST_FLAG_ALIVE)
  5108. rewind_pressed = false;
  5109. #endif
  5110. /* Prevent rewind hold while paused to rewind only one frame */
  5111. if ( runloop_paused
  5112. && rewind_pressed
  5113. && old_rewind_pressed
  5114. && !runloop_st->run_frames_and_pause)
  5115. {
  5116. cbs->poll_cb();
  5117. return RUNLOOP_STATE_PAUSE;
  5118. }
  5119. rewinding = state_manager_check_rewind(
  5120. &runloop_st->rewind_st,
  5121. &runloop_st->current_core,
  5122. rewind_pressed,
  5123. settings->uints.rewind_granularity,
  5124. runloop_paused
  5125. #ifdef HAVE_MENU
  5126. || ( (menu_st->flags & MENU_ST_FLAG_ALIVE)
  5127. && settings->bools.menu_pause_libretro)
  5128. #endif
  5129. ,
  5130. s, sizeof(s), &t);
  5131. old_rewind_pressed = rewind_pressed;
  5132. #if defined(HAVE_GFX_WIDGETS)
  5133. if (widgets_active)
  5134. {
  5135. if (rewinding)
  5136. video_st->flags |= VIDEO_FLAG_WIDGETS_REWINDING;
  5137. else
  5138. video_st->flags &= ~VIDEO_FLAG_WIDGETS_REWINDING;
  5139. }
  5140. else
  5141. #endif
  5142. {
  5143. if (rewinding)
  5144. runloop_msg_queue_push(s, 0, t, true, NULL,
  5145. MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  5146. }
  5147. if (rewinding && runloop_paused
  5148. #ifdef HAVE_MENU
  5149. && !(menu_st->flags & MENU_ST_FLAG_ALIVE)
  5150. #endif
  5151. )
  5152. {
  5153. cbs->poll_cb();
  5154. /* Run a few frames on first press after pausing to
  5155. * prevent going forwards for the first frame */
  5156. if (runloop_st->run_frames_and_pause == -1)
  5157. {
  5158. runloop_st->flags &= ~RUNLOOP_FLAG_PAUSED;
  5159. runloop_st->run_frames_and_pause = 3;
  5160. }
  5161. return RUNLOOP_STATE_ITERATE;
  5162. }
  5163. #endif
  5164. }
  5165. }
  5166. /* Check pause hotkey in menu */
  5167. #ifdef HAVE_MENU
  5168. if (menu_st->flags & MENU_ST_FLAG_ALIVE)
  5169. {
  5170. static bool old_pause_pressed = false;
  5171. bool pause_pressed = BIT256_GET(current_bits, RARCH_PAUSE_TOGGLE);
  5172. /* Decide pause hotkey */
  5173. runloop_pause_toggle(&runloop_paused_hotkey,
  5174. pause_pressed, old_pause_pressed,
  5175. focused, old_focus);
  5176. old_focus = focused;
  5177. old_pause_pressed = pause_pressed;
  5178. }
  5179. #endif
  5180. #ifdef HAVE_MENU
  5181. /* Stop checking the rest of the hotkeys if menu is alive */
  5182. if (menu_st->flags & MENU_ST_FLAG_ALIVE)
  5183. {
  5184. float fastforward_ratio = runloop_get_fastforward_ratio(settings,
  5185. &runloop_st->fastmotion_override.current);
  5186. if (!settings->bools.menu_throttle_framerate && !fastforward_ratio)
  5187. return RUNLOOP_STATE_MENU_ITERATE;
  5188. return RUNLOOP_STATE_END;
  5189. }
  5190. #endif
  5191. #ifdef HAVE_NETWORKING
  5192. if (netplay_driver_ctl(RARCH_NETPLAY_CTL_ALLOW_PAUSE, NULL))
  5193. #endif
  5194. if (pause_nonactive)
  5195. focused = is_focused;
  5196. /* Check pause hotkey */
  5197. {
  5198. static bool old_frameadvance = false;
  5199. static bool old_pause_pressed = false;
  5200. static bool pauseframeadvance = false;
  5201. bool frameadvance_pressed = false;
  5202. bool frameadvance_trigger = false;
  5203. bool pause_pressed = BIT256_GET(current_bits, RARCH_PAUSE_TOGGLE);
  5204. /* Reset frameadvance pause when triggering pause */
  5205. if (pause_pressed)
  5206. pauseframeadvance = false;
  5207. /* Allow unpausing with Start */
  5208. if (runloop_paused && settings->bools.pause_on_disconnect)
  5209. pause_pressed |= BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_START);
  5210. #ifdef HAVE_CHEEVOS
  5211. /* Make sure not to evaluate this before calling menu_driver_iterate
  5212. * as that may change its value */
  5213. cheevos_hardcore_active = rcheevos_hardcore_active();
  5214. if (cheevos_hardcore_active)
  5215. {
  5216. static int unpaused_frames = 0;
  5217. if (runloop_st->flags & RUNLOOP_FLAG_PAUSED)
  5218. unpaused_frames = 0;
  5219. else
  5220. /* Frame advance is not allowed when achievement hardcore is active */
  5221. {
  5222. /* Limit pause to approximately three times per second (depending on core framerate) */
  5223. if (unpaused_frames < 20)
  5224. {
  5225. ++unpaused_frames;
  5226. pause_pressed = false;
  5227. }
  5228. }
  5229. }
  5230. else
  5231. #endif
  5232. {
  5233. frameadvance_pressed = BIT256_GET(current_bits, RARCH_FRAMEADVANCE);
  5234. frameadvance_trigger = frameadvance_pressed && !old_frameadvance;
  5235. /* FRAMEADVANCE will set us into special pause mode. */
  5236. if (frameadvance_trigger)
  5237. {
  5238. pauseframeadvance = true;
  5239. if (!(runloop_st->flags & RUNLOOP_FLAG_PAUSED))
  5240. pause_pressed = true;
  5241. }
  5242. }
  5243. /* Decide pause hotkey */
  5244. runloop_pause_toggle(&runloop_paused_hotkey,
  5245. pause_pressed, old_pause_pressed,
  5246. focused, old_focus);
  5247. old_focus = focused;
  5248. old_pause_pressed = pause_pressed;
  5249. old_frameadvance = frameadvance_pressed;
  5250. if (runloop_st->flags & RUNLOOP_FLAG_PAUSED)
  5251. {
  5252. #ifdef HAVE_REWIND
  5253. /* Frame advance must also trigger rewind save */
  5254. if (frameadvance_trigger && runloop_paused)
  5255. state_manager_check_rewind(
  5256. &runloop_st->rewind_st,
  5257. &runloop_st->current_core,
  5258. false,
  5259. settings->uints.rewind_granularity,
  5260. false,
  5261. NULL, 0, NULL);
  5262. #endif
  5263. /* Check if it's not oneshot */
  5264. #ifdef HAVE_REWIND
  5265. if (!(frameadvance_trigger || BIT256_GET(current_bits, RARCH_REWIND)))
  5266. #else
  5267. if (!frameadvance_trigger)
  5268. #endif
  5269. focused = false;
  5270. else
  5271. runloop_paused = false;
  5272. /* Drop to RUNLOOP_STATE_POLLED_AND_SLEEP if frameadvance is triggered */
  5273. if (pauseframeadvance)
  5274. runloop_paused = false;
  5275. }
  5276. }
  5277. /* Check recording hotkey */
  5278. HOTKEY_CHECK(RARCH_RECORDING_TOGGLE, CMD_EVENT_RECORDING_TOGGLE, true, NULL);
  5279. /* Check streaming hotkey */
  5280. HOTKEY_CHECK(RARCH_STREAMING_TOGGLE, CMD_EVENT_STREAMING_TOGGLE, true, NULL);
  5281. /* Check Run-Ahead hotkey */
  5282. HOTKEY_CHECK(RARCH_RUNAHEAD_TOGGLE, CMD_EVENT_RUNAHEAD_TOGGLE, true, NULL);
  5283. /* Check Preemptive Frames hotkey */
  5284. HOTKEY_CHECK(RARCH_PREEMPT_TOGGLE, CMD_EVENT_PREEMPT_TOGGLE, true, NULL);
  5285. /* Check AI Service hotkey */
  5286. HOTKEY_CHECK(RARCH_AI_SERVICE, CMD_EVENT_AI_SERVICE_TOGGLE, true, NULL);
  5287. #ifdef HAVE_NETWORKING
  5288. /* Check netplay hotkeys */
  5289. HOTKEY_CHECK(RARCH_NETPLAY_PING_TOGGLE, CMD_EVENT_NETPLAY_PING_TOGGLE, true, NULL);
  5290. HOTKEY_CHECK(RARCH_NETPLAY_GAME_WATCH, CMD_EVENT_NETPLAY_GAME_WATCH, true, NULL);
  5291. HOTKEY_CHECK(RARCH_NETPLAY_PLAYER_CHAT, CMD_EVENT_NETPLAY_PLAYER_CHAT, true, NULL);
  5292. HOTKEY_CHECK(RARCH_NETPLAY_FADE_CHAT_TOGGLE, CMD_EVENT_NETPLAY_FADE_CHAT_TOGGLE, true, NULL);
  5293. #endif
  5294. #ifdef HAVE_ACCESSIBILITY
  5295. #ifdef HAVE_TRANSLATE
  5296. /* Copy over the retropad state to a buffer for the translate service
  5297. to send off if it's run. */
  5298. if (settings->bools.ai_service_enable)
  5299. {
  5300. input_st->ai_gamepad_state[0] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_B);
  5301. input_st->ai_gamepad_state[1] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_Y);
  5302. input_st->ai_gamepad_state[2] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_SELECT);
  5303. input_st->ai_gamepad_state[3] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_START);
  5304. input_st->ai_gamepad_state[4] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_UP);
  5305. input_st->ai_gamepad_state[5] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_DOWN);
  5306. input_st->ai_gamepad_state[6] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_LEFT);
  5307. input_st->ai_gamepad_state[7] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_RIGHT);
  5308. input_st->ai_gamepad_state[8] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_A);
  5309. input_st->ai_gamepad_state[9] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_X);
  5310. input_st->ai_gamepad_state[10] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_L);
  5311. input_st->ai_gamepad_state[11] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_R);
  5312. input_st->ai_gamepad_state[12] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_L2);
  5313. input_st->ai_gamepad_state[13] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_R2);
  5314. input_st->ai_gamepad_state[14] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_L3);
  5315. input_st->ai_gamepad_state[15] = BIT256_GET(current_bits, RETRO_DEVICE_ID_JOYPAD_R3);
  5316. }
  5317. #endif
  5318. #endif
  5319. if (!focused && !runloop_paused)
  5320. {
  5321. cbs->poll_cb();
  5322. return RUNLOOP_STATE_POLLED_AND_SLEEP;
  5323. }
  5324. /* Apply any pending fastmotion override parameters */
  5325. if (runloop_st->fastmotion_override.pending)
  5326. {
  5327. runloop_apply_fastmotion_override(runloop_st, settings);
  5328. runloop_st->fastmotion_override.pending = false;
  5329. }
  5330. /* Check fastmotion hotkeys */
  5331. /* To avoid continuous switching if we hold the button down, we require
  5332. * that the button must go from pressed to unpressed back to pressed
  5333. * to be able to toggle between them.
  5334. */
  5335. if (!runloop_st->fastmotion_override.current.inhibit_toggle)
  5336. {
  5337. static bool old_button_state = false;
  5338. static bool old_hold_button_state = false;
  5339. bool new_button_state = BIT256_GET(
  5340. current_bits, RARCH_FAST_FORWARD_KEY);
  5341. bool new_hold_button_state = BIT256_GET(
  5342. current_bits, RARCH_FAST_FORWARD_HOLD_KEY);
  5343. bool check2 = new_button_state
  5344. && !old_button_state;
  5345. if (!check2)
  5346. check2 = old_hold_button_state != new_hold_button_state;
  5347. /* Don't allow fastmotion while paused */
  5348. if (runloop_paused)
  5349. {
  5350. check2 = true;
  5351. new_button_state = false;
  5352. new_hold_button_state = false;
  5353. input_st->flags |= INP_FLAG_NONBLOCKING;
  5354. }
  5355. if (check2)
  5356. {
  5357. if (input_st->flags & INP_FLAG_NONBLOCKING)
  5358. {
  5359. input_st->flags &= ~INP_FLAG_NONBLOCKING;
  5360. runloop_st->flags &= ~RUNLOOP_FLAG_FASTMOTION;
  5361. runloop_st->fastforward_after_frames = 1;
  5362. }
  5363. else
  5364. {
  5365. input_st->flags |= INP_FLAG_NONBLOCKING;
  5366. runloop_st->flags |= RUNLOOP_FLAG_FASTMOTION;
  5367. command_event(CMD_EVENT_SET_FRAME_LIMIT, NULL);
  5368. }
  5369. driver_set_nonblock_state();
  5370. /* Reset frame time counter when toggling
  5371. * fast-forward off, if required */
  5372. if ( !(runloop_st->flags & RUNLOOP_FLAG_FASTMOTION)
  5373. && settings->bools.frame_time_counter_reset_after_fastforwarding)
  5374. video_st->frame_time_count = 0;
  5375. }
  5376. old_button_state = new_button_state;
  5377. old_hold_button_state = new_hold_button_state;
  5378. }
  5379. /* Display fast-forward notification, unless
  5380. * disabled via override */
  5381. if (!runloop_st->fastmotion_override.current.fastforward ||
  5382. runloop_st->fastmotion_override.current.notification)
  5383. {
  5384. /* > Use widgets, if enabled */
  5385. #if defined(HAVE_GFX_WIDGETS)
  5386. if (widgets_active)
  5387. {
  5388. if (settings->bools.notification_show_fast_forward)
  5389. {
  5390. if (runloop_st->flags & RUNLOOP_FLAG_FASTMOTION)
  5391. video_st->flags |= VIDEO_FLAG_WIDGETS_FAST_FORWARD;
  5392. else
  5393. video_st->flags &= ~VIDEO_FLAG_WIDGETS_FAST_FORWARD;
  5394. }
  5395. else
  5396. video_st->flags &= ~VIDEO_FLAG_WIDGETS_FAST_FORWARD;
  5397. }
  5398. else
  5399. #endif
  5400. {
  5401. /* > If widgets are disabled, display fast-forward
  5402. * status via OSD text for 1 frame every frame */
  5403. if ( (runloop_st->flags & RUNLOOP_FLAG_FASTMOTION)
  5404. && settings->bools.notification_show_fast_forward)
  5405. runloop_msg_queue_push(
  5406. msg_hash_to_str(MSG_FAST_FORWARD), 1, 1, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  5407. }
  5408. }
  5409. #if defined(HAVE_GFX_WIDGETS)
  5410. else
  5411. video_st->flags &= ~VIDEO_FLAG_WIDGETS_FAST_FORWARD;
  5412. #endif
  5413. #ifdef HAVE_CHEEVOS
  5414. if (!cheevos_hardcore_active)
  5415. #endif
  5416. {
  5417. {
  5418. /* Check slowmotion hotkeys */
  5419. static bool old_slowmotion_button_state = false;
  5420. static bool old_slowmotion_hold_button_state = false;
  5421. bool new_slowmotion_button_state = BIT256_GET(
  5422. current_bits, RARCH_SLOWMOTION_KEY);
  5423. bool new_slowmotion_hold_button_state = BIT256_GET(
  5424. current_bits, RARCH_SLOWMOTION_HOLD_KEY);
  5425. /* Don't allow slowmotion while paused */
  5426. if (runloop_paused)
  5427. {
  5428. new_slowmotion_button_state = false;
  5429. new_slowmotion_hold_button_state = false;
  5430. }
  5431. if (new_slowmotion_button_state && !old_slowmotion_button_state)
  5432. {
  5433. if (!(runloop_st->flags & RUNLOOP_FLAG_SLOWMOTION))
  5434. runloop_st->flags |= RUNLOOP_FLAG_SLOWMOTION;
  5435. else
  5436. runloop_st->flags &= ~RUNLOOP_FLAG_SLOWMOTION;
  5437. }
  5438. else if (old_slowmotion_hold_button_state != new_slowmotion_hold_button_state)
  5439. {
  5440. if (new_slowmotion_hold_button_state)
  5441. runloop_st->flags |= RUNLOOP_FLAG_SLOWMOTION;
  5442. else
  5443. runloop_st->flags &= ~RUNLOOP_FLAG_SLOWMOTION;
  5444. }
  5445. if (runloop_st->flags & RUNLOOP_FLAG_SLOWMOTION)
  5446. {
  5447. if (settings->uints.video_black_frame_insertion)
  5448. if (!(runloop_st->flags & RUNLOOP_FLAG_IDLE))
  5449. video_driver_cached_frame();
  5450. #if defined(HAVE_GFX_WIDGETS)
  5451. if (!widgets_active)
  5452. #endif
  5453. {
  5454. #ifdef HAVE_REWIND
  5455. struct state_manager_rewind_state
  5456. *rewind_st = &runloop_st->rewind_st;
  5457. if (rewind_st->flags
  5458. & STATE_MGR_REWIND_ST_FLAG_FRAME_IS_REVERSED)
  5459. runloop_msg_queue_push(
  5460. msg_hash_to_str(MSG_SLOW_MOTION_REWIND), 1, 1, false, NULL,
  5461. MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  5462. else
  5463. #endif
  5464. runloop_msg_queue_push(
  5465. msg_hash_to_str(MSG_SLOW_MOTION), 1, 1, false,
  5466. NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  5467. }
  5468. }
  5469. old_slowmotion_button_state = new_slowmotion_button_state;
  5470. old_slowmotion_hold_button_state = new_slowmotion_hold_button_state;
  5471. }
  5472. }
  5473. /* Check save state slot hotkeys */
  5474. {
  5475. static bool old_should_slot_increase = false;
  5476. static bool old_should_slot_decrease = false;
  5477. bool should_slot_increase = BIT256_GET(
  5478. current_bits, RARCH_STATE_SLOT_PLUS);
  5479. bool should_slot_decrease = BIT256_GET(
  5480. current_bits, RARCH_STATE_SLOT_MINUS);
  5481. bool check1 = true;
  5482. bool check2 = should_slot_increase && !old_should_slot_increase;
  5483. int addition = 1;
  5484. int state_slot = settings->ints.state_slot;
  5485. if (!check2)
  5486. {
  5487. check2 = should_slot_decrease && !old_should_slot_decrease;
  5488. check1 = state_slot > -1;
  5489. addition = -1;
  5490. /* Wrap-around to 999 */
  5491. if (check2 && !check1 && state_slot + addition < -1)
  5492. {
  5493. state_slot = 1000;
  5494. check1 = true;
  5495. }
  5496. }
  5497. /* Wrap-around to -1 (Auto) */
  5498. else if (state_slot + addition > 999)
  5499. state_slot = -2;
  5500. if (check2)
  5501. {
  5502. size_t _len;
  5503. char msg[128];
  5504. int cur_state_slot = state_slot + addition;
  5505. if (check1)
  5506. configuration_set_int(settings, settings->ints.state_slot,
  5507. cur_state_slot);
  5508. _len = strlcpy(msg, msg_hash_to_str(MSG_STATE_SLOT), sizeof(msg));
  5509. snprintf(msg + _len, sizeof(msg) - _len,
  5510. ": %d", settings->ints.state_slot);
  5511. if (cur_state_slot < 0)
  5512. strlcat(msg, " (Auto)", sizeof(msg));
  5513. #ifdef HAVE_GFX_WIDGETS
  5514. if (dispwidget_get_ptr()->active)
  5515. gfx_widget_set_generic_message(msg, 1000);
  5516. else
  5517. #endif
  5518. runloop_msg_queue_push(msg, 2, 60, true, NULL,
  5519. MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  5520. RARCH_LOG("[State]: %s\n", msg);
  5521. }
  5522. old_should_slot_increase = should_slot_increase;
  5523. old_should_slot_decrease = should_slot_decrease;
  5524. }
  5525. /* Check replay slot hotkeys */
  5526. {
  5527. static bool old_should_replay_slot_increase = false;
  5528. static bool old_should_replay_slot_decrease = false;
  5529. bool should_slot_increase = BIT256_GET(
  5530. current_bits, RARCH_REPLAY_SLOT_PLUS);
  5531. bool should_slot_decrease = BIT256_GET(
  5532. current_bits, RARCH_REPLAY_SLOT_MINUS);
  5533. bool check1 = true;
  5534. bool check2 = should_slot_increase && !old_should_replay_slot_increase;
  5535. int addition = 1;
  5536. int replay_slot = settings->ints.replay_slot;
  5537. if (!check2)
  5538. {
  5539. check2 = should_slot_decrease && !old_should_replay_slot_decrease;
  5540. check1 = replay_slot > -1;
  5541. addition = -1;
  5542. /* Wrap-around to 999 */
  5543. if (check2 && !check1 && replay_slot + addition < -1)
  5544. {
  5545. replay_slot = 1000;
  5546. check1 = true;
  5547. }
  5548. }
  5549. /* Wrap-around to -1 (Auto) */
  5550. else if (replay_slot + addition > 999)
  5551. replay_slot = -2;
  5552. if (check2)
  5553. {
  5554. size_t _len;
  5555. char msg[128];
  5556. int cur_replay_slot = replay_slot + addition;
  5557. if (check1)
  5558. configuration_set_int(settings, settings->ints.replay_slot,
  5559. cur_replay_slot);
  5560. _len = strlcpy(msg, msg_hash_to_str(MSG_REPLAY_SLOT), sizeof(msg));
  5561. snprintf(msg + _len, sizeof(msg) - _len,
  5562. ": %d", settings->ints.replay_slot);
  5563. if (cur_replay_slot < 0)
  5564. strlcat(msg, " (Auto)", sizeof(msg));
  5565. #ifdef HAVE_GFX_WIDGETS
  5566. if (dispwidget_get_ptr()->active)
  5567. gfx_widget_set_generic_message(msg, 1000);
  5568. else
  5569. #endif
  5570. runloop_msg_queue_push(msg, 2, 60, true, NULL,
  5571. MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  5572. RARCH_LOG("[Replay]: %s\n", msg);
  5573. }
  5574. old_should_replay_slot_increase = should_slot_increase;
  5575. old_should_replay_slot_decrease = should_slot_decrease;
  5576. }
  5577. /* Check save state hotkeys */
  5578. HOTKEY_CHECK(RARCH_SAVE_STATE_KEY, CMD_EVENT_SAVE_STATE, true, NULL);
  5579. HOTKEY_CHECK(RARCH_LOAD_STATE_KEY, CMD_EVENT_LOAD_STATE, true, NULL);
  5580. /* Check reset hotkey */
  5581. HOTKEY_CHECK(RARCH_RESET, CMD_EVENT_RESET, true, NULL);
  5582. /* Check VRR runloop hotkey */
  5583. HOTKEY_CHECK(RARCH_VRR_RUNLOOP_TOGGLE, CMD_EVENT_VRR_RUNLOOP_TOGGLE, true, NULL);
  5584. /* Check bsv movie hotkeys */
  5585. HOTKEY_CHECK(RARCH_PLAY_REPLAY_KEY, CMD_EVENT_PLAY_REPLAY, true, NULL);
  5586. HOTKEY_CHECK(RARCH_RECORD_REPLAY_KEY, CMD_EVENT_RECORD_REPLAY, true, NULL);
  5587. HOTKEY_CHECK(RARCH_HALT_REPLAY_KEY, CMD_EVENT_HALT_REPLAY, true, NULL);
  5588. /* Check Disc Control hotkeys */
  5589. HOTKEY_CHECK3(
  5590. RARCH_DISK_EJECT_TOGGLE, CMD_EVENT_DISK_EJECT_TOGGLE,
  5591. RARCH_DISK_NEXT, CMD_EVENT_DISK_NEXT,
  5592. RARCH_DISK_PREV, CMD_EVENT_DISK_PREV);
  5593. /* Check cheat hotkeys */
  5594. HOTKEY_CHECK3(
  5595. RARCH_CHEAT_INDEX_PLUS, CMD_EVENT_CHEAT_INDEX_PLUS,
  5596. RARCH_CHEAT_INDEX_MINUS, CMD_EVENT_CHEAT_INDEX_MINUS,
  5597. RARCH_CHEAT_TOGGLE, CMD_EVENT_CHEAT_TOGGLE);
  5598. #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
  5599. /* Check shader hotkeys */
  5600. HOTKEY_CHECK3(
  5601. RARCH_SHADER_NEXT, CMD_EVENT_SHADER_NEXT,
  5602. RARCH_SHADER_PREV, CMD_EVENT_SHADER_PREV,
  5603. RARCH_SHADER_TOGGLE, CMD_EVENT_SHADER_TOGGLE);
  5604. if (settings->bools.video_shader_watch_files)
  5605. {
  5606. static rarch_timer_t timer = {0};
  5607. static bool need_to_apply = false;
  5608. if (video_shader_check_for_changes())
  5609. {
  5610. need_to_apply = true;
  5611. if (!timer.timer_begin)
  5612. {
  5613. timer.timeout_us = SHADER_FILE_WATCH_DELAY_MSEC * 1000;
  5614. timer.current = cpu_features_get_time_usec();
  5615. timer.timeout_end = timer.current + timer.timeout_us;
  5616. timer.timer_begin = true;
  5617. timer.timer_end = false;
  5618. }
  5619. }
  5620. /* If a file is modified atomically (moved/renamed from a different file),
  5621. * we have no idea how long that might take.
  5622. * If we're trying to re-apply shaders immediately after changes are made
  5623. * to the original file(s), the filesystem might be in an in-between
  5624. * state where the new file hasn't been moved over yet and the original
  5625. * file was already deleted. This leaves us no choice but to wait an
  5626. * arbitrary amount of time and hope for the best.
  5627. */
  5628. if (need_to_apply)
  5629. {
  5630. timer.current = current_time;
  5631. timer.timeout_us = timer.timeout_end - timer.current;
  5632. if ( !timer.timer_end
  5633. && timer.timeout_us <= 0)
  5634. {
  5635. timer.timer_end = true;
  5636. timer.timer_begin = false;
  5637. timer.timeout_end = 0;
  5638. need_to_apply = false;
  5639. command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL);
  5640. }
  5641. }
  5642. }
  5643. if ( settings->uints.video_shader_delay
  5644. && !runloop_st->shader_delay_timer.timer_end)
  5645. {
  5646. if (!runloop_st->shader_delay_timer.timer_begin)
  5647. {
  5648. runloop_st->shader_delay_timer.timeout_us = settings->uints.video_shader_delay * 1000;
  5649. runloop_st->shader_delay_timer.current = cpu_features_get_time_usec();
  5650. runloop_st->shader_delay_timer.timeout_end = runloop_st->shader_delay_timer.current
  5651. + runloop_st->shader_delay_timer.timeout_us;
  5652. runloop_st->shader_delay_timer.timer_begin = true;
  5653. runloop_st->shader_delay_timer.timer_end = false;
  5654. }
  5655. else
  5656. {
  5657. runloop_st->shader_delay_timer.current = current_time;
  5658. runloop_st->shader_delay_timer.timeout_us = runloop_st->shader_delay_timer.timeout_end
  5659. - runloop_st->shader_delay_timer.current;
  5660. if (runloop_st->shader_delay_timer.timeout_us <= 0)
  5661. {
  5662. runloop_st->shader_delay_timer.timer_end = true;
  5663. runloop_st->shader_delay_timer.timer_begin = false;
  5664. runloop_st->shader_delay_timer.timeout_end = 0;
  5665. {
  5666. const char *preset = video_shader_get_current_shader_preset();
  5667. enum rarch_shader_type type = video_shader_parse_type(preset);
  5668. video_shader_apply_shader(settings, type, preset, false);
  5669. }
  5670. }
  5671. }
  5672. }
  5673. #endif
  5674. if (runloop_paused)
  5675. {
  5676. cbs->poll_cb();
  5677. return RUNLOOP_STATE_PAUSE;
  5678. }
  5679. return RUNLOOP_STATE_ITERATE;
  5680. }
  5681. /**
  5682. * runloop_iterate:
  5683. *
  5684. * Run Libretro core in RetroArch for one frame.
  5685. *
  5686. * Returns: 0 on success, 1 if we have to wait until
  5687. * button input in order to wake up the loop,
  5688. * -1 if we forcibly quit out of the RetroArch iteration loop.
  5689. **/
  5690. int runloop_iterate(void)
  5691. {
  5692. int i;
  5693. enum analog_dpad_mode dpad_mode[MAX_USERS];
  5694. input_driver_state_t *input_st = input_state_get_ptr();
  5695. audio_driver_state_t *audio_st = audio_state_get_ptr();
  5696. video_driver_state_t *video_st = video_state_get_ptr();
  5697. recording_state_t *recording_st = recording_state_get_ptr();
  5698. camera_driver_state_t *camera_st = camera_state_get_ptr();
  5699. #if defined(HAVE_COCOATOUCH)
  5700. uico_driver_state_t *uico_st = uico_state_get_ptr();
  5701. #endif
  5702. settings_t *settings = config_get_ptr();
  5703. runloop_state_t *runloop_st = &runloop_state;
  5704. unsigned video_frame_delay = settings->uints.video_frame_delay;
  5705. unsigned video_frame_delay_effective = video_st->frame_delay_effective;
  5706. bool vrr_runloop_enable = settings->bools.vrr_runloop_enable;
  5707. unsigned max_users = settings->uints.input_max_users;
  5708. retro_time_t current_time = cpu_features_get_time_usec();
  5709. #ifdef HAVE_MENU
  5710. #ifdef HAVE_NETWORKING
  5711. bool menu_pause_libretro = settings->bools.menu_pause_libretro &&
  5712. netplay_driver_ctl(RARCH_NETPLAY_CTL_ALLOW_PAUSE, NULL);
  5713. #else
  5714. bool menu_pause_libretro = settings->bools.menu_pause_libretro;
  5715. #endif
  5716. bool core_paused =
  5717. (runloop_st->flags & RUNLOOP_FLAG_PAUSED) ||
  5718. (menu_pause_libretro && (menu_state_get_ptr()->flags & MENU_ST_FLAG_ALIVE));
  5719. #else
  5720. bool core_paused = (runloop_st->flags & RUNLOOP_FLAG_PAUSED);
  5721. #endif
  5722. float slowmotion_ratio = settings->floats.slowmotion_ratio;
  5723. #ifdef HAVE_CHEEVOS
  5724. bool cheevos_enable = settings->bools.cheevos_enable;
  5725. #endif
  5726. bool audio_sync = settings->bools.audio_sync;
  5727. #ifdef HAVE_DISCORD
  5728. discord_state_t *discord_st = discord_state_get_ptr();
  5729. if (discord_st->inited)
  5730. {
  5731. Discord_RunCallbacks();
  5732. #ifdef DISCORD_DISABLE_IO_THREAD
  5733. Discord_UpdateConnection();
  5734. #endif
  5735. }
  5736. #endif
  5737. bool is_need_reinit_drivers = (runloop_st->flags2 & RUNLOOP_FLAG_NEED_REINIT_DRIVERS);
  5738. if (is_need_reinit_drivers) {
  5739. command_event(CMD_EVENT_REINIT, NULL);
  5740. runloop_st->flags2 &= ~RUNLOOP_FLAG_NEED_REINIT_DRIVERS;
  5741. }
  5742. if (runloop_st->frame_time.callback)
  5743. {
  5744. /* Updates frame timing if frame timing callback is in use by the core.
  5745. * Limits frame time if fast forward ratio throttle is enabled. */
  5746. retro_usec_t runloop_last_frame_time = runloop_st->frame_time_last;
  5747. retro_time_t current = current_time;
  5748. bool is_locked_fps = (
  5749. (runloop_st->flags & RUNLOOP_FLAG_PAUSED)
  5750. || (input_st->flags & INP_FLAG_NONBLOCKING))
  5751. | !!recording_st->data;
  5752. retro_time_t delta = (!runloop_last_frame_time || is_locked_fps)
  5753. ? runloop_st->frame_time.reference
  5754. : (current - runloop_last_frame_time);
  5755. if (is_locked_fps)
  5756. runloop_st->frame_time_last = 0;
  5757. else
  5758. {
  5759. runloop_st->frame_time_last = current;
  5760. if (runloop_st->flags & RUNLOOP_FLAG_SLOWMOTION)
  5761. delta /= slowmotion_ratio;
  5762. }
  5763. if (!core_paused)
  5764. runloop_st->frame_time.callback(delta);
  5765. }
  5766. /* Update audio buffer occupancy if buffer status
  5767. * callback is in use by the core */
  5768. if (runloop_st->audio_buffer_status.callback)
  5769. {
  5770. bool audio_buf_active = false;
  5771. unsigned audio_buf_occupancy = 0;
  5772. bool audio_buf_underrun = false;
  5773. if (!( (runloop_st->flags & RUNLOOP_FLAG_PAUSED)
  5774. || !(audio_st->flags & AUDIO_FLAG_ACTIVE)
  5775. || !(audio_st->output_samples_buf))
  5776. && audio_st->current_audio->write_avail
  5777. && audio_st->context_audio_data
  5778. && audio_st->buffer_size)
  5779. {
  5780. size_t audio_buf_avail;
  5781. if ((audio_buf_avail = audio_st->current_audio->write_avail(
  5782. audio_st->context_audio_data)) > audio_st->buffer_size)
  5783. audio_buf_avail = audio_st->buffer_size;
  5784. audio_buf_occupancy = (unsigned)(100 - (audio_buf_avail * 100) /
  5785. audio_st->buffer_size);
  5786. /* Elsewhere, we standardise on a 'low water mark'
  5787. * of 25% of the total audio buffer size - use
  5788. * the same metric here (can be made more sophisticated
  5789. * if required - i.e. determine buffer occupancy in
  5790. * terms of usec, and weigh this against the expected
  5791. * frame time) */
  5792. audio_buf_underrun = audio_buf_occupancy < 25;
  5793. audio_buf_active = true;
  5794. }
  5795. if (!core_paused)
  5796. runloop_st->audio_buffer_status.callback(
  5797. audio_buf_active, audio_buf_occupancy, audio_buf_underrun);
  5798. }
  5799. switch ((enum runloop_state_enum)runloop_check_state(
  5800. global_get_ptr()->error_on_init,
  5801. settings, current_time))
  5802. {
  5803. case RUNLOOP_STATE_QUIT:
  5804. runloop_st->frame_limit_last_time = 0.0;
  5805. runloop_st->flags &= ~RUNLOOP_FLAG_CORE_RUNNING;
  5806. command_event(CMD_EVENT_QUIT, NULL);
  5807. return -1;
  5808. case RUNLOOP_STATE_POLLED_AND_SLEEP:
  5809. #ifdef HAVE_NETWORKING
  5810. /* FIXME: This is an ugly way to tell Netplay this... */
  5811. netplay_driver_ctl(RARCH_NETPLAY_CTL_PAUSE, NULL);
  5812. #endif
  5813. #if defined(HAVE_COCOATOUCH)
  5814. if (!(uico_st->flags & UICO_ST_FLAG_IS_ON_FOREGROUND))
  5815. #endif
  5816. retro_sleep(10);
  5817. return 1;
  5818. case RUNLOOP_STATE_PAUSE:
  5819. #ifdef HAVE_NETWORKING
  5820. /* FIXME: This is an ugly way to tell Netplay this... */
  5821. netplay_driver_ctl(RARCH_NETPLAY_CTL_PAUSE, NULL);
  5822. #endif
  5823. video_driver_cached_frame();
  5824. return 1;
  5825. case RUNLOOP_STATE_END:
  5826. #ifdef HAVE_NETWORKING
  5827. #ifdef HAVE_MENU
  5828. /* FIXME: This is an ugly way to tell Netplay this... */
  5829. if (menu_pause_libretro &&
  5830. netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL)
  5831. )
  5832. netplay_driver_ctl(RARCH_NETPLAY_CTL_PAUSE, NULL);
  5833. #endif
  5834. #endif
  5835. goto end;
  5836. case RUNLOOP_STATE_MENU_ITERATE:
  5837. #ifdef HAVE_NETWORKING
  5838. /* FIXME: This is an ugly way to tell Netplay this... */
  5839. netplay_driver_ctl(RARCH_NETPLAY_CTL_PAUSE, NULL);
  5840. #endif
  5841. return 0;
  5842. case RUNLOOP_STATE_ITERATE:
  5843. runloop_st->flags |= RUNLOOP_FLAG_CORE_RUNNING;
  5844. break;
  5845. }
  5846. #ifdef HAVE_THREADS
  5847. if (runloop_st->flags & RUNLOOP_FLAG_AUTOSAVE)
  5848. autosave_lock();
  5849. #endif
  5850. #ifdef HAVE_BSV_MOVIE
  5851. bsv_movie_next_frame(input_st);
  5852. #endif
  5853. if ( camera_st->cb.caps
  5854. && camera_st->driver
  5855. && camera_st->driver->poll
  5856. && camera_st->data)
  5857. camera_st->driver->poll(camera_st->data,
  5858. camera_st->cb.frame_raw_framebuffer,
  5859. camera_st->cb.frame_opengl_texture);
  5860. /* Update binds for analog dpad modes. */
  5861. for (i = 0; i < (int)max_users; i++)
  5862. {
  5863. dpad_mode[i] = (enum analog_dpad_mode)
  5864. settings->uints.input_analog_dpad_mode[i];
  5865. switch (dpad_mode[i])
  5866. {
  5867. case ANALOG_DPAD_LSTICK:
  5868. case ANALOG_DPAD_RSTICK:
  5869. {
  5870. unsigned mapped_port = settings->uints.input_remap_ports[i];
  5871. if (input_st->analog_requested[mapped_port])
  5872. dpad_mode[i] = ANALOG_DPAD_NONE;
  5873. }
  5874. break;
  5875. case ANALOG_DPAD_LSTICK_FORCED:
  5876. dpad_mode[i] = ANALOG_DPAD_LSTICK;
  5877. break;
  5878. case ANALOG_DPAD_RSTICK_FORCED:
  5879. dpad_mode[i] = ANALOG_DPAD_RSTICK;
  5880. break;
  5881. default:
  5882. break;
  5883. }
  5884. /* Push analog to D-Pad mappings to binds. */
  5885. if (dpad_mode[i] != ANALOG_DPAD_NONE)
  5886. {
  5887. unsigned k;
  5888. unsigned joy_idx = settings->uints.input_joypad_index[i];
  5889. struct retro_keybind *general_binds = input_config_binds[joy_idx];
  5890. struct retro_keybind *auto_binds = input_autoconf_binds[joy_idx];
  5891. unsigned x_plus = RARCH_ANALOG_RIGHT_X_PLUS;
  5892. unsigned y_plus = RARCH_ANALOG_RIGHT_Y_PLUS;
  5893. unsigned x_minus = RARCH_ANALOG_RIGHT_X_MINUS;
  5894. unsigned y_minus = RARCH_ANALOG_RIGHT_Y_MINUS;
  5895. if (dpad_mode[i] == ANALOG_DPAD_LSTICK)
  5896. {
  5897. x_plus = RARCH_ANALOG_LEFT_X_PLUS;
  5898. y_plus = RARCH_ANALOG_LEFT_Y_PLUS;
  5899. x_minus = RARCH_ANALOG_LEFT_X_MINUS;
  5900. y_minus = RARCH_ANALOG_LEFT_Y_MINUS;
  5901. }
  5902. for (k = RETRO_DEVICE_ID_JOYPAD_UP; k <= RETRO_DEVICE_ID_JOYPAD_RIGHT; k++)
  5903. {
  5904. (auto_binds)[k].orig_joyaxis = (auto_binds)[k].joyaxis;
  5905. (general_binds)[k].orig_joyaxis = (general_binds)[k].joyaxis;
  5906. }
  5907. if (!INHERIT_JOYAXIS(auto_binds))
  5908. {
  5909. unsigned j = x_plus + 3;
  5910. /* Inherit joyaxis from analogs. */
  5911. for (k = RETRO_DEVICE_ID_JOYPAD_UP; k <= RETRO_DEVICE_ID_JOYPAD_RIGHT; k++)
  5912. (auto_binds)[k].joyaxis = (auto_binds)[j--].joyaxis;
  5913. }
  5914. if (!INHERIT_JOYAXIS(general_binds))
  5915. {
  5916. unsigned j = x_plus + 3;
  5917. /* Inherit joyaxis from analogs. */
  5918. for (k = RETRO_DEVICE_ID_JOYPAD_UP; k <= RETRO_DEVICE_ID_JOYPAD_RIGHT; k++)
  5919. (general_binds)[k].joyaxis = (general_binds)[j--].joyaxis;
  5920. }
  5921. }
  5922. }
  5923. /* Frame delay */
  5924. if ( !(input_st->flags & INP_FLAG_NONBLOCKING)
  5925. || (runloop_st->flags & RUNLOOP_FLAG_FASTMOTION))
  5926. {
  5927. bool skip_delay = core_paused
  5928. || (runloop_st->flags & RUNLOOP_FLAG_SLOWMOTION)
  5929. || (runloop_st->flags & RUNLOOP_FLAG_FASTMOTION);
  5930. if (settings->bools.video_frame_delay_auto)
  5931. {
  5932. float refresh_rate = settings->floats.video_refresh_rate;
  5933. uint8_t video_swap_interval = runloop_get_video_swap_interval(
  5934. settings->uints.video_swap_interval);
  5935. uint8_t video_bfi = settings->uints.video_black_frame_insertion;
  5936. uint8_t frame_time_interval = 8;
  5937. static uint8_t skip_update = 0;
  5938. static bool skip_delay_prev = false;
  5939. bool frame_time_update =
  5940. /* Skip some initial frames for stabilization */
  5941. video_st->frame_count > frame_time_interval &&
  5942. /* Only update when there are enough frames for averaging */
  5943. video_st->frame_count % frame_time_interval == 0;
  5944. /* A few frames must be ignored after slow+fastmotion/pause
  5945. * is disabled or geometry change is triggered */
  5946. if ( (!skip_delay && skip_delay_prev)
  5947. || video_st->frame_delay_pause)
  5948. {
  5949. skip_update = frame_time_interval * 4;
  5950. video_st->frame_delay_pause = false;
  5951. }
  5952. if (skip_update)
  5953. skip_update--;
  5954. skip_delay_prev = skip_delay;
  5955. /* Always skip when slow+fastmotion/pause is active */
  5956. if (skip_delay_prev)
  5957. skip_update = 1;
  5958. if (skip_update)
  5959. frame_time_update = false;
  5960. /* Black frame insertion + swap interval multiplier */
  5961. refresh_rate = (refresh_rate / (video_bfi + 1.0f) / video_swap_interval);
  5962. /* Set target moderately as half frame time with 0 (Auto) delay */
  5963. if (video_frame_delay == 0)
  5964. video_frame_delay = 1 / refresh_rate * 1000 / 2;
  5965. /* Reset new desired delay target */
  5966. if (video_st->frame_delay_target != video_frame_delay)
  5967. {
  5968. frame_time_update = false;
  5969. video_st->frame_delay_target = video_frame_delay_effective = video_frame_delay;
  5970. RARCH_LOG("[Video]: Frame delay reset to %d ms.\n", video_frame_delay);
  5971. }
  5972. /* Decide what should happen to effective delay */
  5973. if (video_frame_delay_effective > 0 && frame_time_update)
  5974. {
  5975. video_frame_delay_auto_t vfda = {0};
  5976. vfda.frame_time_interval = frame_time_interval;
  5977. vfda.refresh_rate = refresh_rate;
  5978. video_frame_delay_auto(video_st, &vfda);
  5979. if (vfda.delay_decrease > 0)
  5980. {
  5981. video_frame_delay_effective -= vfda.delay_decrease;
  5982. RARCH_LOG("[Video]: Frame delay decrease by %d ms to %d ms due to frame time average: %d > %d.\n",
  5983. vfda.delay_decrease, video_frame_delay_effective, vfda.frame_time_avg, vfda.frame_time_target);
  5984. }
  5985. }
  5986. }
  5987. else
  5988. video_st->frame_delay_target = video_frame_delay_effective = video_frame_delay;
  5989. video_st->frame_delay_effective = video_frame_delay_effective;
  5990. /* Never apply frame delay when slow+fastmotion/pause is active */
  5991. if (video_frame_delay_effective > 0 && !skip_delay)
  5992. retro_sleep(video_frame_delay_effective);
  5993. }
  5994. {
  5995. #ifdef HAVE_RUNAHEAD
  5996. bool run_ahead_enabled = settings->bools.run_ahead_enabled;
  5997. unsigned run_ahead_num_frames = settings->uints.run_ahead_frames;
  5998. bool run_ahead_hide_warnings = settings->bools.run_ahead_hide_warnings;
  5999. bool run_ahead_secondary_instance = settings->bools.run_ahead_secondary_instance;
  6000. /* Run Ahead Feature replaces the call to core_run in this loop */
  6001. bool want_runahead = run_ahead_enabled
  6002. && (run_ahead_num_frames > 0)
  6003. && (runloop_st->flags & RUNLOOP_FLAG_RUNAHEAD_AVAILABLE);
  6004. #ifdef HAVE_NETWORKING
  6005. want_runahead = want_runahead
  6006. && !netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL);
  6007. #endif
  6008. if (want_runahead)
  6009. runahead_run(
  6010. runloop_st,
  6011. run_ahead_num_frames,
  6012. run_ahead_hide_warnings,
  6013. run_ahead_secondary_instance);
  6014. else if (runloop_st->preempt_data)
  6015. preempt_run(runloop_st->preempt_data, runloop_st);
  6016. else
  6017. #endif
  6018. core_run();
  6019. }
  6020. /* Increment runtime tick counter after each call to
  6021. * core_run() or run_ahead() */
  6022. runloop_st->core_runtime_usec += runloop_core_runtime_tick(
  6023. runloop_st,
  6024. slowmotion_ratio,
  6025. current_time);
  6026. #ifdef HAVE_CHEEVOS
  6027. if (cheevos_enable)
  6028. rcheevos_test();
  6029. #endif
  6030. #ifdef HAVE_CHEATS
  6031. cheat_manager_apply_retro_cheats();
  6032. #endif
  6033. #ifdef HAVE_PRESENCE
  6034. presence_update(PRESENCE_GAME);
  6035. #endif
  6036. /* Restores analog D-pad binds temporarily overridden. */
  6037. for (i = 0; i < (int)max_users; i++)
  6038. {
  6039. if (dpad_mode[i] != ANALOG_DPAD_NONE)
  6040. {
  6041. int j;
  6042. unsigned joy_idx = settings->uints.input_joypad_index[i];
  6043. struct retro_keybind *general_binds = input_config_binds[joy_idx];
  6044. struct retro_keybind *auto_binds = input_autoconf_binds[joy_idx];
  6045. for (j = RETRO_DEVICE_ID_JOYPAD_UP; j <= RETRO_DEVICE_ID_JOYPAD_RIGHT; j++)
  6046. {
  6047. (auto_binds)[j].joyaxis = (auto_binds)[j].orig_joyaxis;
  6048. (general_binds)[j].joyaxis = (general_binds)[j].orig_joyaxis;
  6049. }
  6050. }
  6051. }
  6052. #ifdef HAVE_BSV_MOVIE
  6053. bsv_movie_finish_rewind(input_st);
  6054. if (input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_END)
  6055. {
  6056. movie_stop_playback(input_st);
  6057. command_event(CMD_EVENT_PAUSE, NULL);
  6058. }
  6059. if (input_st->bsv_movie_state.flags & BSV_FLAG_MOVIE_END)
  6060. {
  6061. movie_stop_playback(input_st);
  6062. command_event(CMD_EVENT_PAUSE, NULL);
  6063. }
  6064. #endif
  6065. #ifdef HAVE_THREADS
  6066. if (runloop_st->flags & RUNLOOP_FLAG_AUTOSAVE)
  6067. autosave_unlock();
  6068. #endif
  6069. end:
  6070. if (vrr_runloop_enable)
  6071. {
  6072. /* Sync on video only, block audio later. */
  6073. if (runloop_st->fastforward_after_frames && audio_sync)
  6074. {
  6075. if (runloop_st->fastforward_after_frames == 1)
  6076. {
  6077. /* Nonblocking audio */
  6078. if ( (audio_st->flags & AUDIO_FLAG_ACTIVE)
  6079. && (audio_st->context_audio_data))
  6080. audio_st->current_audio->set_nonblock_state(
  6081. audio_st->context_audio_data, true);
  6082. audio_st->chunk_size =
  6083. audio_st->chunk_nonblock_size;
  6084. }
  6085. runloop_st->fastforward_after_frames++;
  6086. if (runloop_st->fastforward_after_frames == 6)
  6087. {
  6088. /* Blocking audio */
  6089. if ( (audio_st->flags & AUDIO_FLAG_ACTIVE)
  6090. && (audio_st->context_audio_data))
  6091. audio_st->current_audio->set_nonblock_state(
  6092. audio_st->context_audio_data,
  6093. audio_sync ? false : true);
  6094. audio_st->chunk_size = audio_st->chunk_block_size;
  6095. runloop_st->fastforward_after_frames = 0;
  6096. }
  6097. }
  6098. if (runloop_st->flags & RUNLOOP_FLAG_FASTMOTION)
  6099. runloop_set_frame_limit(&video_st->av_info,
  6100. runloop_get_fastforward_ratio(settings,
  6101. &runloop_st->fastmotion_override.current));
  6102. else
  6103. runloop_set_frame_limit(&video_st->av_info,
  6104. 1.0f);
  6105. }
  6106. /* if there's a fast forward limit, inject sleeps to keep from going too fast. */
  6107. if (runloop_st->frame_limit_minimum_time)
  6108. {
  6109. const retro_time_t end_frame_time = cpu_features_get_time_usec();
  6110. const retro_time_t to_sleep_ms = (
  6111. ( runloop_st->frame_limit_last_time
  6112. + runloop_st->frame_limit_minimum_time)
  6113. - end_frame_time) / 1000;
  6114. if (to_sleep_ms > 0)
  6115. {
  6116. unsigned sleep_ms = (unsigned)to_sleep_ms;
  6117. /* Combat jitter a bit. */
  6118. runloop_st->frame_limit_last_time +=
  6119. runloop_st->frame_limit_minimum_time;
  6120. if (sleep_ms > 0)
  6121. {
  6122. #if defined(HAVE_COCOATOUCH)
  6123. if (!(uico_state_get_ptr()->flags & UICO_ST_FLAG_IS_ON_FOREGROUND))
  6124. #endif
  6125. retro_sleep(sleep_ms);
  6126. }
  6127. return 1;
  6128. }
  6129. runloop_st->frame_limit_last_time = end_frame_time;
  6130. }
  6131. /* Set paused state after x frames */
  6132. if (runloop_st->run_frames_and_pause > 0)
  6133. {
  6134. runloop_st->run_frames_and_pause--;
  6135. if (!runloop_st->run_frames_and_pause)
  6136. runloop_st->flags |= RUNLOOP_FLAG_PAUSED;
  6137. }
  6138. return 0;
  6139. }
  6140. void runloop_msg_queue_deinit(void)
  6141. {
  6142. runloop_state_t *runloop_st = &runloop_state;
  6143. RUNLOOP_MSG_QUEUE_LOCK(runloop_st);
  6144. msg_queue_deinitialize(&runloop_st->msg_queue);
  6145. RUNLOOP_MSG_QUEUE_UNLOCK(runloop_st);
  6146. #ifdef HAVE_THREADS
  6147. slock_free(runloop_st->msg_queue_lock);
  6148. runloop_st->msg_queue_lock = NULL;
  6149. #endif
  6150. runloop_st->msg_queue_size = 0;
  6151. }
  6152. void runloop_msg_queue_init(void)
  6153. {
  6154. runloop_state_t *runloop_st = &runloop_state;
  6155. runloop_msg_queue_deinit();
  6156. msg_queue_initialize(&runloop_st->msg_queue, 8);
  6157. #ifdef HAVE_THREADS
  6158. runloop_st->msg_queue_lock = slock_new();
  6159. #endif
  6160. }
  6161. void runloop_task_msg_queue_push(
  6162. retro_task_t *task, const char *msg,
  6163. unsigned prio, unsigned duration,
  6164. bool flush)
  6165. {
  6166. #if defined(HAVE_GFX_WIDGETS)
  6167. #ifdef HAVE_MENU
  6168. struct menu_state *menu_st = menu_state_get_ptr();
  6169. #endif
  6170. #ifdef HAVE_ACCESSIBILITY
  6171. access_state_t *access_st = access_state_get_ptr();
  6172. settings_t *settings = config_get_ptr();
  6173. bool accessibility_enable = settings->bools.accessibility_enable;
  6174. unsigned accessibility_narrator_speech_speed = settings->uints.accessibility_narrator_speech_speed;
  6175. #endif
  6176. runloop_state_t *runloop_st = &runloop_state;
  6177. dispgfx_widget_t *p_dispwidget = dispwidget_get_ptr();
  6178. bool widgets_active = p_dispwidget->active;
  6179. if (widgets_active && task->title && !task->mute)
  6180. {
  6181. RUNLOOP_MSG_QUEUE_LOCK(runloop_st);
  6182. ui_companion_driver_msg_queue_push(msg,
  6183. prio, task ? duration : duration * 60 / 1000, flush);
  6184. #ifdef HAVE_ACCESSIBILITY
  6185. if (is_accessibility_enabled(
  6186. accessibility_enable,
  6187. access_st->enabled))
  6188. accessibility_speak_priority(
  6189. accessibility_enable,
  6190. accessibility_narrator_speech_speed,
  6191. (char*)msg, 0);
  6192. #endif
  6193. gfx_widgets_msg_queue_push(
  6194. task,
  6195. msg,
  6196. duration,
  6197. NULL,
  6198. (enum message_queue_icon)MESSAGE_QUEUE_CATEGORY_INFO,
  6199. (enum message_queue_category)MESSAGE_QUEUE_ICON_DEFAULT,
  6200. prio,
  6201. flush,
  6202. #ifdef HAVE_MENU
  6203. menu_st->flags & MENU_ST_FLAG_ALIVE
  6204. #else
  6205. false
  6206. #endif
  6207. );
  6208. RUNLOOP_MSG_QUEUE_UNLOCK(runloop_st);
  6209. }
  6210. else
  6211. #endif
  6212. runloop_msg_queue_push(msg, prio, duration, flush, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
  6213. }
  6214. bool runloop_get_current_savestate_path(char *path, size_t len)
  6215. {
  6216. settings_t *settings = config_get_ptr();
  6217. int state_slot = settings ? settings->ints.state_slot : 0;
  6218. return runloop_get_savestate_path(path, len, state_slot);
  6219. }
  6220. bool runloop_get_savestate_path(char *path, size_t len, int state_slot)
  6221. {
  6222. runloop_state_t *runloop_st = &runloop_state;
  6223. const char *name_savestate = NULL;
  6224. if (!path)
  6225. return false;
  6226. name_savestate = runloop_st->name.savestate;
  6227. if (string_is_empty(name_savestate))
  6228. return false;
  6229. if (state_slot < 0)
  6230. fill_pathname_join_delim(path, name_savestate, "auto", '.', len);
  6231. else
  6232. {
  6233. size_t _len = strlcpy(path, name_savestate, len);
  6234. if (state_slot > 0)
  6235. snprintf(path + _len, len - _len, "%d", state_slot);
  6236. }
  6237. return true;
  6238. }
  6239. bool runloop_get_current_replay_path(char *path, size_t len)
  6240. {
  6241. settings_t *settings = config_get_ptr();
  6242. int slot = settings ? settings->ints.replay_slot : 0;
  6243. return runloop_get_replay_path(path, len, slot);
  6244. }
  6245. bool runloop_get_replay_path(char *path, size_t len, unsigned slot)
  6246. {
  6247. size_t _len;
  6248. runloop_state_t *runloop_st = &runloop_state;
  6249. const char *name_replay = NULL;
  6250. if (!path)
  6251. return false;
  6252. name_replay = runloop_st->name.replay;
  6253. if (string_is_empty(name_replay))
  6254. return false;
  6255. _len = strlcpy(path, name_replay, len);
  6256. if (slot >= 0)
  6257. snprintf(path + _len, len - _len, "%d", slot);
  6258. return true;
  6259. }
  6260. bool runloop_get_entry_state_path(char *path, size_t len, unsigned slot)
  6261. {
  6262. size_t _len;
  6263. runloop_state_t *runloop_st = &runloop_state;
  6264. const char *name_savestate = NULL;
  6265. if (!path || !slot)
  6266. return false;
  6267. name_savestate = runloop_st->name.savestate;
  6268. if (string_is_empty(name_savestate))
  6269. return false;
  6270. _len = strlcpy(path, name_savestate, len);
  6271. snprintf(path + _len, len - _len, "%d.entry", slot);
  6272. return true;
  6273. }
  6274. void runloop_set_current_core_type(
  6275. enum rarch_core_type type, bool explicitly_set)
  6276. {
  6277. runloop_state_t *runloop_st = &runloop_state;
  6278. if (runloop_st->flags & RUNLOOP_FLAG_HAS_SET_CORE)
  6279. return;
  6280. if (explicitly_set)
  6281. {
  6282. runloop_st->flags |= RUNLOOP_FLAG_HAS_SET_CORE;
  6283. runloop_st->explicit_current_core_type = type;
  6284. }
  6285. runloop_st->current_core_type = type;
  6286. }
  6287. bool core_set_default_callbacks(void *data)
  6288. {
  6289. struct retro_callbacks *cbs = (struct retro_callbacks*)data;
  6290. retro_input_state_t state_cb = core_input_state_poll_return_cb();
  6291. cbs->frame_cb = video_driver_frame;
  6292. cbs->sample_cb = audio_driver_sample;
  6293. cbs->sample_batch_cb = audio_driver_sample_batch;
  6294. cbs->state_cb = state_cb;
  6295. cbs->poll_cb = input_driver_poll;
  6296. return true;
  6297. }
  6298. #ifdef HAVE_NETWORKING
  6299. /**
  6300. * core_set_netplay_callbacks:
  6301. *
  6302. * Set the I/O callbacks to use netplay's interceding callback system. Should
  6303. * only be called while initializing netplay.
  6304. **/
  6305. bool core_set_netplay_callbacks(void)
  6306. {
  6307. runloop_state_t *runloop_st = &runloop_state;
  6308. /* Force normal poll type for netplay. */
  6309. runloop_st->current_core.poll_type = POLL_TYPE_NORMAL;
  6310. /* And use netplay's interceding callbacks */
  6311. runloop_st->current_core.retro_set_video_refresh(video_frame_net);
  6312. runloop_st->current_core.retro_set_audio_sample(audio_sample_net);
  6313. runloop_st->current_core.retro_set_audio_sample_batch(audio_sample_batch_net);
  6314. runloop_st->current_core.retro_set_input_state(input_state_net);
  6315. return true;
  6316. }
  6317. /**
  6318. * core_unset_netplay_callbacks
  6319. *
  6320. * Unset the I/O callbacks from having used netplay's interceding callback
  6321. * system. Should only be called while uninitializing netplay.
  6322. */
  6323. bool core_unset_netplay_callbacks(void)
  6324. {
  6325. struct retro_callbacks cbs;
  6326. runloop_state_t *runloop_st = &runloop_state;
  6327. if (!core_set_default_callbacks(&cbs))
  6328. return false;
  6329. runloop_st->current_core.retro_set_video_refresh(cbs.frame_cb);
  6330. runloop_st->current_core.retro_set_audio_sample(cbs.sample_cb);
  6331. runloop_st->current_core.retro_set_audio_sample_batch(cbs.sample_batch_cb);
  6332. runloop_st->current_core.retro_set_input_state(cbs.state_cb);
  6333. return true;
  6334. }
  6335. #endif
  6336. bool core_set_cheat(retro_ctx_cheat_info_t *info)
  6337. {
  6338. runloop_state_t *runloop_st = &runloop_state;
  6339. #if defined(HAVE_RUNAHEAD) && (defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB))
  6340. settings_t *settings = config_get_ptr();
  6341. bool run_ahead_enabled = false;
  6342. unsigned run_ahead_frames = 0;
  6343. bool run_ahead_secondary_instance = false;
  6344. bool want_runahead = false;
  6345. if (settings)
  6346. {
  6347. run_ahead_enabled = settings->bools.run_ahead_enabled;
  6348. run_ahead_frames = settings->uints.run_ahead_frames;
  6349. run_ahead_secondary_instance = settings->bools.run_ahead_secondary_instance;
  6350. want_runahead = run_ahead_enabled
  6351. && (run_ahead_frames > 0)
  6352. && (runloop_st->flags & RUNLOOP_FLAG_RUNAHEAD_AVAILABLE);
  6353. #ifdef HAVE_NETWORKING
  6354. if (want_runahead)
  6355. want_runahead = !netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL);
  6356. #endif
  6357. }
  6358. #endif
  6359. runloop_st->current_core.retro_cheat_set(info->index, info->enabled, info->code);
  6360. #if defined(HAVE_RUNAHEAD) && (defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB))
  6361. if ( (want_runahead)
  6362. && (run_ahead_secondary_instance)
  6363. && (runloop_st->flags & RUNLOOP_FLAG_RUNAHEAD_SECONDARY_CORE_AVAILABLE)
  6364. && (secondary_core_ensure_exists(runloop_st, settings))
  6365. && (runloop_st->secondary_core.retro_cheat_set))
  6366. runloop_st->secondary_core.retro_cheat_set(
  6367. info->index, info->enabled, info->code);
  6368. #endif
  6369. return true;
  6370. }
  6371. bool core_reset_cheat(void)
  6372. {
  6373. runloop_state_t *runloop_st = &runloop_state;
  6374. #if defined(HAVE_RUNAHEAD) && (defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB))
  6375. settings_t *settings = config_get_ptr();
  6376. bool run_ahead_enabled = false;
  6377. unsigned run_ahead_frames = 0;
  6378. bool run_ahead_secondary_instance = false;
  6379. bool want_runahead = false;
  6380. if (settings)
  6381. {
  6382. run_ahead_enabled = settings->bools.run_ahead_enabled;
  6383. run_ahead_frames = settings->uints.run_ahead_frames;
  6384. run_ahead_secondary_instance = settings->bools.run_ahead_secondary_instance;
  6385. want_runahead = run_ahead_enabled
  6386. && (run_ahead_frames > 0)
  6387. && (runloop_st->flags & RUNLOOP_FLAG_RUNAHEAD_AVAILABLE);
  6388. #ifdef HAVE_NETWORKING
  6389. if (want_runahead)
  6390. want_runahead = !netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL);
  6391. #endif
  6392. }
  6393. #endif
  6394. runloop_st->current_core.retro_cheat_reset();
  6395. #if defined(HAVE_RUNAHEAD) && (defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB))
  6396. if ( (want_runahead)
  6397. && (run_ahead_secondary_instance)
  6398. && (runloop_st->flags & RUNLOOP_FLAG_RUNAHEAD_SECONDARY_CORE_AVAILABLE)
  6399. && (secondary_core_ensure_exists(runloop_st, settings))
  6400. && (runloop_st->secondary_core.retro_cheat_reset))
  6401. runloop_st->secondary_core.retro_cheat_reset();
  6402. #endif
  6403. return true;
  6404. }
  6405. bool core_set_poll_type(unsigned type)
  6406. {
  6407. runloop_state_t *runloop_st = &runloop_state;
  6408. runloop_st->current_core.poll_type = type;
  6409. return true;
  6410. }
  6411. bool core_set_controller_port_device(retro_ctx_controller_info_t *pad)
  6412. {
  6413. runloop_state_t *runloop_st = &runloop_state;
  6414. input_driver_state_t *input_st = input_state_get_ptr();
  6415. if (!pad)
  6416. return false;
  6417. /* We are potentially 'connecting' a entirely different
  6418. * type of virtual input device, which may or may not
  6419. * support analog inputs. We therefore have to reset
  6420. * the 'analog input requested' flag for this port - but
  6421. * since port mapping is arbitrary/mutable, it is easiest
  6422. * to simply reset the flags for all ports.
  6423. * Correct values will be registered at the next call
  6424. * of 'input_state()' */
  6425. memset(&input_st->analog_requested, 0,
  6426. sizeof(input_st->analog_requested));
  6427. #if defined(HAVE_RUNAHEAD)
  6428. #if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)
  6429. runahead_remember_controller_port_device(runloop_st, pad->port, pad->device);
  6430. #endif
  6431. #endif
  6432. runloop_st->current_core.retro_set_controller_port_device(pad->port, pad->device);
  6433. return true;
  6434. }
  6435. bool core_get_memory(retro_ctx_memory_info_t *info)
  6436. {
  6437. runloop_state_t *runloop_st = &runloop_state;
  6438. if (!info)
  6439. return false;
  6440. info->size = runloop_st->current_core.retro_get_memory_size(info->id);
  6441. info->data = runloop_st->current_core.retro_get_memory_data(info->id);
  6442. return true;
  6443. }
  6444. bool core_load_game(retro_ctx_load_content_info_t *load_info)
  6445. {
  6446. bool game_loaded = false;
  6447. runloop_state_t *runloop_st = &runloop_state;
  6448. video_driver_set_cached_frame_ptr(NULL);
  6449. #ifdef HAVE_RUNAHEAD
  6450. runahead_set_load_content_info(runloop_st, load_info);
  6451. #if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)
  6452. runahead_clear_controller_port_map(runloop_st);
  6453. #endif
  6454. #endif
  6455. set_save_state_in_background(false);
  6456. if (load_info && load_info->special)
  6457. game_loaded = runloop_st->current_core.retro_load_game_special(
  6458. load_info->special->id, load_info->info, load_info->content->size);
  6459. else if (load_info && !string_is_empty(load_info->content->elems[0].data))
  6460. game_loaded = runloop_st->current_core.retro_load_game(load_info->info);
  6461. else if (content_get_flags() & CONTENT_ST_FLAG_CORE_DOES_NOT_NEED_CONTENT)
  6462. game_loaded = runloop_st->current_core.retro_load_game(NULL);
  6463. if (game_loaded)
  6464. {
  6465. /* If 'game_loaded' is true at this point, then
  6466. * core is actually running; register that any
  6467. * changes to global remap-related parameters
  6468. * should be reset once core is deinitialised */
  6469. input_state_get_ptr()->flags |= INP_FLAG_REMAPPING_CACHE_ACTIVE;
  6470. runloop_st->current_core.flags |= RETRO_CORE_FLAG_GAME_LOADED;
  6471. return true;
  6472. }
  6473. runloop_st->current_core.flags &= ~RETRO_CORE_FLAG_GAME_LOADED;
  6474. return false;
  6475. }
  6476. bool core_get_system_info(struct retro_system_info *system)
  6477. {
  6478. runloop_state_t *runloop_st = &runloop_state;
  6479. if (!system)
  6480. return false;
  6481. runloop_st->current_core.retro_get_system_info(system);
  6482. return true;
  6483. }
  6484. bool core_unserialize(retro_ctx_serialize_info_t *info)
  6485. {
  6486. runloop_state_t *runloop_st = &runloop_state;
  6487. if (!info || !runloop_st->current_core.retro_unserialize(info->data_const, info->size))
  6488. return false;
  6489. #ifdef HAVE_NETWORKING
  6490. netplay_driver_ctl(RARCH_NETPLAY_CTL_LOAD_SAVESTATE, info);
  6491. #endif
  6492. #if HAVE_RUNAHEAD
  6493. command_event(CMD_EVENT_PREEMPT_RESET_BUFFER, NULL);
  6494. #endif
  6495. return true;
  6496. }
  6497. bool core_unserialize_special(retro_ctx_serialize_info_t *info)
  6498. {
  6499. bool ret;
  6500. runloop_state_t *runloop_st = &runloop_state;
  6501. if (!info)
  6502. return false;
  6503. runloop_st->flags |= RUNLOOP_FLAG_REQUEST_SPECIAL_SAVESTATE;
  6504. ret = runloop_st->current_core.retro_unserialize(info->data_const, info->size);
  6505. runloop_st->flags &= ~RUNLOOP_FLAG_REQUEST_SPECIAL_SAVESTATE;
  6506. #ifdef HAVE_NETWORKING
  6507. if (ret)
  6508. netplay_driver_ctl(RARCH_NETPLAY_CTL_LOAD_SAVESTATE, info);
  6509. #endif
  6510. return ret;
  6511. }
  6512. bool core_serialize(retro_ctx_serialize_info_t *info)
  6513. {
  6514. runloop_state_t *runloop_st = &runloop_state;
  6515. if (!info || !runloop_st->current_core.retro_serialize(info->data, info->size))
  6516. return false;
  6517. return true;
  6518. }
  6519. bool core_serialize_special(retro_ctx_serialize_info_t *info)
  6520. {
  6521. bool ret;
  6522. runloop_state_t *runloop_st = &runloop_state;
  6523. if (!info)
  6524. return false;
  6525. runloop_st->flags |= RUNLOOP_FLAG_REQUEST_SPECIAL_SAVESTATE;
  6526. ret = runloop_st->current_core.retro_serialize(
  6527. info->data, info->size);
  6528. runloop_st->flags &= ~RUNLOOP_FLAG_REQUEST_SPECIAL_SAVESTATE;
  6529. return ret;
  6530. }
  6531. bool core_serialize_size(retro_ctx_size_info_t *info)
  6532. {
  6533. runloop_state_t *runloop_st = &runloop_state;
  6534. if (!info)
  6535. return false;
  6536. info->size = runloop_st->current_core.retro_serialize_size();
  6537. return true;
  6538. }
  6539. bool core_serialize_size_special(retro_ctx_size_info_t *info)
  6540. {
  6541. runloop_state_t *runloop_st = &runloop_state;
  6542. if (!info)
  6543. return false;
  6544. runloop_st->flags |= RUNLOOP_FLAG_REQUEST_SPECIAL_SAVESTATE;
  6545. info->size = runloop_st->current_core.retro_serialize_size();
  6546. runloop_st->flags &= ~RUNLOOP_FLAG_REQUEST_SPECIAL_SAVESTATE;
  6547. return true;
  6548. }
  6549. uint64_t core_serialization_quirks(void)
  6550. {
  6551. runloop_state_t *runloop_st = &runloop_state;
  6552. return runloop_st->current_core.serialization_quirks_v;
  6553. }
  6554. void core_reset(void)
  6555. {
  6556. runloop_state_t *runloop_st = &runloop_state;
  6557. video_driver_set_cached_frame_ptr(NULL);
  6558. runloop_st->current_core.retro_reset();
  6559. }
  6560. void core_run(void)
  6561. {
  6562. runloop_state_t *runloop_st = &runloop_state;
  6563. struct retro_core_t *
  6564. current_core = &runloop_st->current_core;
  6565. const enum poll_type_override_t
  6566. core_poll_type_override = runloop_st->core_poll_type_override;
  6567. unsigned new_poll_type = (core_poll_type_override != POLL_TYPE_OVERRIDE_DONTCARE)
  6568. ? (core_poll_type_override - 1)
  6569. : current_core->poll_type;
  6570. bool early_polling = new_poll_type == POLL_TYPE_EARLY;
  6571. bool late_polling = new_poll_type == POLL_TYPE_LATE;
  6572. #ifdef HAVE_NETWORKING
  6573. bool netplay_preframe = netplay_driver_ctl(
  6574. RARCH_NETPLAY_CTL_PRE_FRAME, NULL);
  6575. if (!netplay_preframe)
  6576. {
  6577. /* Paused due to netplay. We must poll and display something so that a
  6578. * netplay peer pausing doesn't just hang. */
  6579. input_driver_poll();
  6580. video_driver_cached_frame();
  6581. return;
  6582. }
  6583. #endif
  6584. if (early_polling)
  6585. input_driver_poll();
  6586. else if (late_polling)
  6587. current_core->flags &= ~RETRO_CORE_FLAG_INPUT_POLLED;
  6588. current_core->retro_run();
  6589. if ( late_polling
  6590. && (!(current_core->flags & RETRO_CORE_FLAG_INPUT_POLLED)))
  6591. input_driver_poll();
  6592. #ifdef HAVE_NETWORKING
  6593. netplay_driver_ctl(RARCH_NETPLAY_CTL_POST_FRAME, NULL);
  6594. #endif
  6595. }
  6596. bool core_has_set_input_descriptor(void)
  6597. {
  6598. runloop_state_t *runloop_st = &runloop_state;
  6599. return ((runloop_st->current_core.flags &
  6600. RETRO_CORE_FLAG_HAS_SET_INPUT_DESCRIPTORS) > 0);
  6601. }
  6602. char *crt_switch_core_name(void)
  6603. {
  6604. return (char*)runloop_state.system.info.library_name;
  6605. }
  6606. void runloop_path_set_basename(const char *path)
  6607. {
  6608. runloop_state_t *runloop_st = &runloop_state;
  6609. char *dst = NULL;
  6610. path_set(RARCH_PATH_CONTENT, path);
  6611. path_set(RARCH_PATH_BASENAME, path);
  6612. #ifdef HAVE_COMPRESSION
  6613. /* Removing extension is a bit tricky for compressed files.
  6614. * Basename means:
  6615. * /file/to/path/game.extension should be:
  6616. * /file/to/path/game
  6617. *
  6618. * Two things to consider here are: /file/to/path/ is expected
  6619. * to be a directory and "game" is a single file. This is used for
  6620. * states and srm default paths.
  6621. *
  6622. * For compressed files we have:
  6623. *
  6624. * /file/to/path/comp.7z#game.extension and
  6625. * /file/to/path/comp.7z#folder/game.extension
  6626. *
  6627. * The choice I take here is:
  6628. * /file/to/path/game as basename. We might end up in a writable
  6629. * directory then and the name of srm and states are meaningful.
  6630. *
  6631. */
  6632. path_basedir_wrapper(runloop_st->runtime_content_path_basename);
  6633. if (!string_is_empty(runloop_st->runtime_content_path_basename))
  6634. fill_pathname_dir(runloop_st->runtime_content_path_basename, path, "", sizeof(runloop_st->runtime_content_path_basename));
  6635. #endif
  6636. if ((dst = strrchr(runloop_st->runtime_content_path_basename, '.')))
  6637. *dst = '\0';
  6638. }
  6639. void runloop_path_set_names(void)
  6640. {
  6641. runloop_state_t *runloop_st = &runloop_state;
  6642. if (!retroarch_override_setting_is_set(
  6643. RARCH_OVERRIDE_SETTING_SAVE_PATH, NULL))
  6644. {
  6645. size_t len = strlcpy(runloop_st->name.savefile,
  6646. runloop_st->runtime_content_path_basename,
  6647. sizeof(runloop_st->name.savefile));
  6648. runloop_st->name.savefile[len ] = '.';
  6649. runloop_st->name.savefile[len+1] = 's';
  6650. runloop_st->name.savefile[len+2] = 'r';
  6651. runloop_st->name.savefile[len+3] = 'm';
  6652. runloop_st->name.savefile[len+4] = '\0';
  6653. }
  6654. if (!retroarch_override_setting_is_set(
  6655. RARCH_OVERRIDE_SETTING_STATE_PATH, NULL))
  6656. {
  6657. size_t len = strlcpy(
  6658. runloop_st->name.savestate,
  6659. runloop_st->runtime_content_path_basename,
  6660. sizeof(runloop_st->name.savestate));
  6661. runloop_st->name.savestate[len ] = '.';
  6662. runloop_st->name.savestate[len+1] = 's';
  6663. runloop_st->name.savestate[len+2] = 't';
  6664. runloop_st->name.savestate[len+3] = 'a';
  6665. runloop_st->name.savestate[len+4] = 't';
  6666. runloop_st->name.savestate[len+5] = 'e';
  6667. runloop_st->name.savestate[len+6] = '\0';
  6668. }
  6669. #ifdef HAVE_BSV_MOVIE
  6670. if (!retroarch_override_setting_is_set(
  6671. RARCH_OVERRIDE_SETTING_STATE_PATH, NULL))
  6672. {
  6673. size_t len = strlcpy(
  6674. runloop_st->name.replay,
  6675. runloop_st->runtime_content_path_basename,
  6676. sizeof(runloop_st->name.replay));
  6677. runloop_st->name.replay[len ] = '.';
  6678. runloop_st->name.replay[len+1] = 'r';
  6679. runloop_st->name.replay[len+2] = 'e';
  6680. runloop_st->name.replay[len+3] = 'p';
  6681. runloop_st->name.replay[len+4] = 'l';
  6682. runloop_st->name.replay[len+5] = 'a';
  6683. runloop_st->name.replay[len+6] = 'y';
  6684. runloop_st->name.replay[len+7] = '\0';
  6685. }
  6686. #endif
  6687. #ifdef HAVE_CHEATS
  6688. if (!string_is_empty(runloop_st->runtime_content_path_basename))
  6689. {
  6690. size_t len = strlcpy(
  6691. runloop_st->name.cheatfile,
  6692. runloop_st->runtime_content_path_basename,
  6693. sizeof(runloop_st->name.cheatfile));
  6694. runloop_st->name.cheatfile[len ] = '.';
  6695. runloop_st->name.cheatfile[len+1] = 'c';
  6696. runloop_st->name.cheatfile[len+2] = 'h';
  6697. runloop_st->name.cheatfile[len+3] = 't';
  6698. runloop_st->name.cheatfile[len+4] = '\0';
  6699. }
  6700. #endif
  6701. }
  6702. void runloop_path_set_redirect(settings_t *settings,
  6703. const char *old_savefile_dir,
  6704. const char *old_savestate_dir)
  6705. {
  6706. char content_dir_name[PATH_MAX_LENGTH];
  6707. char new_savefile_dir[PATH_MAX_LENGTH];
  6708. char new_savestate_dir[PATH_MAX_LENGTH];
  6709. runloop_state_t *runloop_st = &runloop_state;
  6710. struct retro_system_info *system = &runloop_st->system.info;
  6711. bool sort_savefiles_enable = settings->bools.sort_savefiles_enable;
  6712. bool sort_savefiles_by_content_enable = settings->bools.sort_savefiles_by_content_enable;
  6713. bool sort_savestates_enable = settings->bools.sort_savestates_enable;
  6714. bool sort_savestates_by_content_enable = settings->bools.sort_savestates_by_content_enable;
  6715. bool savefiles_in_content_dir = settings->bools.savefiles_in_content_dir;
  6716. bool savestates_in_content_dir = settings->bools.savestates_in_content_dir;
  6717. content_dir_name[0] = '\0';
  6718. /* Initialize current save directories
  6719. * with the values from the config. */
  6720. strlcpy(new_savefile_dir, old_savefile_dir, sizeof(new_savefile_dir));
  6721. strlcpy(new_savestate_dir, old_savestate_dir, sizeof(new_savestate_dir));
  6722. /* Get content directory name, if per-content-directory
  6723. * saves/states are enabled */
  6724. if ((sort_savefiles_by_content_enable ||
  6725. sort_savestates_by_content_enable) &&
  6726. !string_is_empty(runloop_st->runtime_content_path_basename))
  6727. fill_pathname_parent_dir_name(content_dir_name,
  6728. runloop_st->runtime_content_path_basename,
  6729. sizeof(content_dir_name));
  6730. if (system && !string_is_empty(system->library_name))
  6731. {
  6732. #ifdef HAVE_MENU
  6733. if (!string_is_equal(system->library_name,
  6734. msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORE)))
  6735. #endif
  6736. {
  6737. /* Per-core and/or per-content-directory saves */
  6738. if ((sort_savefiles_enable || sort_savefiles_by_content_enable)
  6739. && !string_is_empty(old_savefile_dir))
  6740. {
  6741. /* Append content directory name to save location */
  6742. if (sort_savefiles_by_content_enable)
  6743. fill_pathname_join_special(
  6744. new_savefile_dir,
  6745. old_savefile_dir,
  6746. content_dir_name,
  6747. sizeof(new_savefile_dir));
  6748. /* Append library_name to the save location */
  6749. if (sort_savefiles_enable)
  6750. fill_pathname_join(
  6751. new_savefile_dir,
  6752. new_savefile_dir,
  6753. system->library_name,
  6754. sizeof(new_savefile_dir));
  6755. /* If path doesn't exist, try to create it,
  6756. * if everything fails revert to the original path. */
  6757. if (!path_is_directory(new_savefile_dir))
  6758. if (!path_mkdir(new_savefile_dir))
  6759. {
  6760. RARCH_LOG("%s %s\n",
  6761. msg_hash_to_str(MSG_REVERTING_SAVEFILE_DIRECTORY_TO),
  6762. old_savefile_dir);
  6763. strlcpy(new_savefile_dir, old_savefile_dir, sizeof(new_savefile_dir));
  6764. }
  6765. }
  6766. /* Per-core and/or per-content-directory savestates */
  6767. if ((sort_savestates_enable || sort_savestates_by_content_enable)
  6768. && !string_is_empty(old_savestate_dir))
  6769. {
  6770. /* Append content directory name to savestate location */
  6771. if (sort_savestates_by_content_enable)
  6772. fill_pathname_join_special(
  6773. new_savestate_dir,
  6774. old_savestate_dir,
  6775. content_dir_name,
  6776. sizeof(new_savestate_dir));
  6777. /* Append library_name to the savestate location */
  6778. if (sort_savestates_enable)
  6779. {
  6780. fill_pathname_join(
  6781. new_savestate_dir,
  6782. new_savestate_dir,
  6783. system->library_name,
  6784. sizeof(new_savestate_dir));
  6785. }
  6786. /* If path doesn't exist, try to create it.
  6787. * If everything fails, revert to the original path. */
  6788. if (!path_is_directory(new_savestate_dir))
  6789. if (!path_mkdir(new_savestate_dir))
  6790. {
  6791. RARCH_LOG("%s %s\n",
  6792. msg_hash_to_str(MSG_REVERTING_SAVESTATE_DIRECTORY_TO),
  6793. old_savestate_dir);
  6794. strlcpy(new_savestate_dir,
  6795. old_savestate_dir,
  6796. sizeof(new_savestate_dir));
  6797. }
  6798. }
  6799. }
  6800. }
  6801. /* Set savefile directory if empty to content directory */
  6802. if (string_is_empty(new_savefile_dir) || savefiles_in_content_dir)
  6803. {
  6804. strlcpy(new_savefile_dir,
  6805. runloop_st->runtime_content_path_basename,
  6806. sizeof(new_savefile_dir));
  6807. path_basedir(new_savefile_dir);
  6808. if (string_is_empty(new_savefile_dir))
  6809. RARCH_LOG("Cannot resolve save file path.\n");
  6810. else if (sort_savefiles_enable || sort_savefiles_by_content_enable)
  6811. RARCH_LOG("Saving files in content directory is set. This overrides other save file directory settings.\n");
  6812. }
  6813. /* Set savestate directory if empty based on content directory */
  6814. if (string_is_empty(new_savestate_dir) || savestates_in_content_dir)
  6815. {
  6816. strlcpy(new_savestate_dir,
  6817. runloop_st->runtime_content_path_basename,
  6818. sizeof(new_savestate_dir));
  6819. path_basedir(new_savestate_dir);
  6820. if (string_is_empty(new_savestate_dir))
  6821. RARCH_LOG("Cannot resolve save state file path.\n");
  6822. else if (sort_savestates_enable || sort_savestates_by_content_enable)
  6823. RARCH_LOG("Saving save states in content directory is set. This overrides other save state file directory settings.\n");
  6824. }
  6825. #ifdef HAVE_NETWORKING
  6826. /* Special save directory for netplay clients. */
  6827. if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL) &&
  6828. !netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_SERVER, NULL))
  6829. {
  6830. fill_pathname_join(new_savefile_dir, new_savefile_dir, ".netplay",
  6831. sizeof(new_savefile_dir));
  6832. if (!path_is_directory(new_savefile_dir) &&
  6833. !path_mkdir(new_savefile_dir))
  6834. path_basedir(new_savefile_dir);
  6835. }
  6836. #endif
  6837. if (system && !string_is_empty(system->library_name))
  6838. {
  6839. bool savefile_is_dir = path_is_directory(new_savefile_dir);
  6840. bool savestate_is_dir = path_is_directory(new_savestate_dir);
  6841. if (savefile_is_dir)
  6842. strlcpy(runloop_st->name.savefile, new_savefile_dir,
  6843. sizeof(runloop_st->name.savefile));
  6844. else
  6845. savefile_is_dir = path_is_directory(runloop_st->name.savefile);
  6846. if (savestate_is_dir)
  6847. {
  6848. strlcpy(runloop_st->name.savestate, new_savestate_dir,
  6849. sizeof(runloop_st->name.savestate));
  6850. strlcpy(runloop_st->name.replay, new_savestate_dir,
  6851. sizeof(runloop_st->name.replay));
  6852. }
  6853. else
  6854. savestate_is_dir = path_is_directory(runloop_st->name.savestate);
  6855. if (savefile_is_dir)
  6856. {
  6857. fill_pathname_dir(runloop_st->name.savefile,
  6858. !string_is_empty(runloop_st->runtime_content_path_basename)
  6859. ? runloop_st->runtime_content_path_basename
  6860. : system->library_name,
  6861. FILE_PATH_SRM_EXTENSION,
  6862. sizeof(runloop_st->name.savefile));
  6863. RARCH_LOG("[Overrides]: %s \"%s\".\n",
  6864. msg_hash_to_str(MSG_REDIRECTING_SAVEFILE_TO),
  6865. runloop_st->name.savefile);
  6866. }
  6867. if (savestate_is_dir)
  6868. {
  6869. fill_pathname_dir(runloop_st->name.savestate,
  6870. !string_is_empty(runloop_st->runtime_content_path_basename)
  6871. ? runloop_st->runtime_content_path_basename
  6872. : system->library_name,
  6873. FILE_PATH_STATE_EXTENSION,
  6874. sizeof(runloop_st->name.savestate));
  6875. fill_pathname_dir(runloop_st->name.replay,
  6876. !string_is_empty(runloop_st->runtime_content_path_basename)
  6877. ? runloop_st->runtime_content_path_basename
  6878. : system->library_name,
  6879. FILE_PATH_BSV_EXTENSION,
  6880. sizeof(runloop_st->name.replay));
  6881. RARCH_LOG("[Overrides]: %s \"%s\".\n",
  6882. msg_hash_to_str(MSG_REDIRECTING_SAVESTATE_TO),
  6883. runloop_st->name.savestate);
  6884. }
  6885. #ifdef HAVE_CHEATS
  6886. if (path_is_directory(runloop_st->name.cheatfile))
  6887. {
  6888. fill_pathname_dir(runloop_st->name.cheatfile,
  6889. !string_is_empty(runloop_st->runtime_content_path_basename)
  6890. ? runloop_st->runtime_content_path_basename
  6891. : system->library_name,
  6892. FILE_PATH_CHT_EXTENSION,
  6893. sizeof(runloop_st->name.cheatfile));
  6894. RARCH_LOG("[Overrides]: %s \"%s\".\n",
  6895. msg_hash_to_str(MSG_REDIRECTING_CHEATFILE_TO),
  6896. runloop_st->name.cheatfile);
  6897. }
  6898. #endif
  6899. }
  6900. dir_set(RARCH_DIR_CURRENT_SAVEFILE, new_savefile_dir);
  6901. dir_set(RARCH_DIR_CURRENT_SAVESTATE, new_savestate_dir);
  6902. }
  6903. void runloop_path_deinit_subsystem(void)
  6904. {
  6905. runloop_state_t *runloop_st = &runloop_state;
  6906. if (runloop_st->subsystem_fullpaths)
  6907. string_list_free(runloop_st->subsystem_fullpaths);
  6908. runloop_st->subsystem_fullpaths = NULL;
  6909. }
  6910. void runloop_path_set_special(char **argv, unsigned num_content)
  6911. {
  6912. unsigned i;
  6913. char str[PATH_MAX_LENGTH];
  6914. union string_list_elem_attr attr;
  6915. bool is_dir = false;
  6916. struct string_list subsystem_paths = {0};
  6917. runloop_state_t *runloop_st = &runloop_state;
  6918. const char *savestate_dir = runloop_st->savestate_dir;
  6919. /* First content file is the significant one. */
  6920. runloop_path_set_basename(argv[0]);
  6921. string_list_initialize(&subsystem_paths);
  6922. runloop_st->subsystem_fullpaths = string_list_new();
  6923. attr.i = 0;
  6924. for (i = 0; i < num_content; i++)
  6925. {
  6926. string_list_append(runloop_st->subsystem_fullpaths, argv[i], attr);
  6927. strlcpy(str, argv[i], sizeof(str));
  6928. path_remove_extension(str);
  6929. string_list_append(&subsystem_paths, path_basename(str), attr);
  6930. }
  6931. str[0] = '\0';
  6932. string_list_join_concat(str, sizeof(str), &subsystem_paths, " + ");
  6933. string_list_deinitialize(&subsystem_paths);
  6934. /* We defer SRAM path updates until we can resolve it.
  6935. * It is more complicated for special content types. */
  6936. is_dir = path_is_directory(savestate_dir);
  6937. if (is_dir)
  6938. {
  6939. strlcpy(runloop_st->name.savestate, savestate_dir,
  6940. sizeof(runloop_st->name.savestate)); /* TODO/FIXME - why are we setting this string here but then later overwriting it later with fil_pathname_dir? */
  6941. strlcpy(runloop_st->name.replay, savestate_dir,
  6942. sizeof(runloop_st->name.replay)); /* TODO/FIXME - as above */
  6943. }
  6944. else
  6945. is_dir = path_is_directory(runloop_st->name.savestate);
  6946. if (is_dir)
  6947. {
  6948. fill_pathname_dir(runloop_st->name.savestate,
  6949. str,
  6950. ".state",
  6951. sizeof(runloop_st->name.savestate));
  6952. fill_pathname_dir(runloop_st->name.replay,
  6953. str,
  6954. ".replay",
  6955. sizeof(runloop_st->name.replay));
  6956. RARCH_LOG("%s \"%s\".\n",
  6957. msg_hash_to_str(MSG_REDIRECTING_SAVESTATE_TO),
  6958. runloop_st->name.savestate);
  6959. }
  6960. }